perm filename IOSER.TNX[10X,AIL]1 blob sn#093271 filedate 1974-03-26 generic text, type T, neo UTF8
COMMENT ⊗   VALID 00092 PAGES VERSION 0(0)
RECORD PAGE   DESCRIPTION
 00001 00001
 00011 00002	TENX<THE ENTIRE FILE IS FOR TENEX ONLY
 00016 00003	COMPIL(PAT,<OPEN,LOOKUP,ENTER,USETI,USETO,MTAPE,TENXFI,RELEASE,CLOSE,CLOSIN,CLOSO,GETCHAN,CVJFN,RENAME>
 00024 00004	DSCR  PROCEDURE LOOKUP(INTEGER CHNL STRING FILE REFERENCE INTEGER FLAG)
 00028 00005	HERE(ENTER)
 00031 00006	DSCR
 00034 00007	DSCR PROCEDURE USETI,USETO(INTEGER CHANNEL,BLOCK)
 00036 00008	DSCR	PROCEDURE CLOSE(INTEGER CHANNEL)
 00037 00009	HERE(RELEASE)
 00038 00010	DSCR	
 00039 00011	DSCR	STRING PROCEDURE TENXFI(STRING DECFILE)
 00043 00012	DSCR
 00045 00013	COMPIL(JOBINF,<ODTIM,IDTIM,RUNTM,GTAD,GJINF>,<ZSETST,ZADJST,X22,X33,X44,.SKIP.,CATCHR>
 00046 00014	
 00047 00015	DSCR INTEGER SIMPLE PROCEDURE RUNTM(INTEGER FORK REFERENCE INTEGER CONSOLE)
 00048 00016	DSCR INTEGER SIMPLE PROCEDURE GTAD
 00049 00017	DSCR INTEGER SIMPLE PROCEDURE GJINF(REFERENCE INTEGER LOGDIR,CONDIR,TTYNO)
 00050 00018	ENDCOM(JOBINF)
 00051 00019	COMPIL(DIRECT,<STDIR,DIRST>,<X22,X33,CATCHR,ZSETST,ZADJST.SKIP.>
 00053 00020	DSCR STRING SIMPLE PROCEDURE DIRST(INTEGER I)
 00054 00021	COMPIL(RUNPRG,<RUNPRG>,<X22,X33,CATCHR>,<RUNPRG -- RUN A PROGRAM>)
 00059 00022	COMPIL(OPF,<OPENFILE,SETINPUT,SETPL,INDEXFILE>,<.SKIP.>,<OPENFILE -- OPEN A FILE>)
 00067 00023	DSCR PROCEDURE SETINPUT(INTEGER CHAN REFERENCE INTEGER COUNT,BR,EOF)
 00068 00024	DSCR
 00070 00025	DSCR
 00072 00026	COMPIL(GTJFN,<GTJFN,GTJFNL>,<.SKIP.,SETCHN,CATCHR,X11,X22,X44>,<GTJFN -- GET A JFN>)
 00074 00027	DSCR INTEGER PROCEDURE GTJFNL(STRING ORIG INTEGER FLAGS, XWDJFN!JFN
 00077 00028	COMPIL(FILINF,<GNJFN,DELF,UNDELETE,SIZEF,JFNS,OPENF,CFILE,CLOSF,RLJFN,GTSTS,STSTS,RNAMF>
 00079 00029	DSCR	PROCEDURE DELF(INTEGER CHAN)
 00080 00030	DSCR	PROCEDURE UNDELETE(INTEGER CHAN)
 00081 00031	DSCR	INTEGER PROCEDURE SIZEF(INTEGER JFN)
 00082 00032	
 00083 00033	DSCR SIMPLE PROCEDURE OPENF(INTEGER JFN,FLAGS)
 00085 00034	
 00089 00035	DSCR SIMPLE PROCEDURE CLOSF(INTEGER JFN)
 00091 00036	DSCR SIMPLE PROCEDURE RLJFN(INTEGER JFN)
 00092 00037	DSCR INTEGER SIMPLE PROCEDURE GTSTS(INTEGER JFN)
 00093 00038	DSCR BOOLEAN SIMPLE PROCEDURE STSTS(INTEGER JFN,STATUS)
 00094 00039	DSCR BOOLEAN SIMPLE PROCEDURE RNAMF(INTEGER EXISTINGJFN,NEWJFN)
 00095 00040	COMPIL(DEVINF,<CNDIR,ASND,RELD,GDSTS,SDSTS,STDEV,DEVST>
 00097 00041	DSCR BOOLEAN PROCEDURE ASND(INTEGER DEVICE)
 00098 00042	DSCR BOOLEAN PROCEDURE RELD(INTEGER DEVICE)
 00099 00043	DSCR INTEGER SIMPLE PROCEDURE GDSTS(INTEGER CHAN REFERENCE INTEGER WORDCNT)
 00100 00044	DSCR PROCEDURE SDSTS(INTEGER JFN,NEWSTATUS)
 00101 00045	DSCR INTEGER PROCEDURE STDEV(STRING S)
 00102 00046	
 00103 00047	
 00104 00048	COMPIL(FIO,<OUT,CHAROUT,LINOUT,GTFDB>
 00107 00049	DSCR	PROCEDURE LINOUT(INTEGER JFN,VALUE)
 00109 00050	DSCR 	STRSND,STRSN0
 00114 00051	DSCR	SIMPLE PROCEDURE GTFDB(INTEGER JFN REFERENCE INTEGER ARRAY BUF)
 00115 00052	COMPIL(BINROU,<WORDIN,WORDOUT,ARRYIN,ARRYOUT,MTOPR,SFPTR,RFPTR,BKJFN,RFBSZ>
 00117 00053	DSCR SIMPLE PROCEDURE WORDOUT(INTEGER JFN,BYTE)
 00118 00054	DSCR SIMPLE PROCEDURE ARRYIN(INTEGER JFN REFERENCE INTEGER LOC INTEGER COUNT)
 00121 00055	DSCR SIMPLE PROCEDURE ARRYOUT(INTEGER JFN REFERENCE INTEGER LOC INTEGER COUNT)
 00123 00056	DSCR SIMPLE PROCEDURE MTOPR(INTEGER JFN,FUNCTION,VALUE)
 00124 00057	DSCR SIMPLE PROCEDURE SFPTR(INTEGER JFN,POINTER)
 00125 00058	DSCR INTEGER SIMPLE PROCEDURE RFPTR(INTEGER JFN)
 00126 00059	DSCR SIMPLE PROCEDURE BKJFN(INTEGER JFN)
 00127 00060	DSCR INTEGER SIMPLE PROCEDURE RFBSZ(INTEGER JFN)
 00128 00061	IMSSS,<
 00130 00062	DSCR SIMPLE PROCEDURE 
 00131 00063	COMPIL(DEVS,<DEVTYPE,DVCHR,ERSTR>
 00132 00064	DSCR INTEGER SIMPLE PROCEDURE DVCHR(INTEGER JFN REFERENCE INTEGER AC1,AC3)
 00133 00065	DSCR SIMPLE PROCEDURE ERSTR(INTEGER ERRNO,FORK)
 00135 00066	COMPIL(UTILITY,<SETCHN,ZSETST,ZADJST,.RESET>
 00140 00067	DSCR STRING SIMPLE PROCEDURE ZADJST(INTEGER CNTEST,BP)
 00143 00068	DSCR
 00147 00069	COMPIL(TTM,<RFMOD,SFMOD,RFCOC,SFCOC>
 00149 00070	COMPIL(PAGES,<PMAP>,<SAVE,RESTR,X44>
 00150 00071	IMSSS,<
 00151 00072	DSCR STRING SIMPLE PROCEDURE INTTY
 00153 00073	NOIMSSS<NON-IMSSS VERSION OF INTTY FOR THOSE WHO SUFFER
 00157 00074	 TTY FUNCTIONS 
 00160 00075	HERE(PBIN)
 00170 00076	Filnam 
 00173 00077	Flscan 
 00175 00078	COMPIL(INP,<INPUT,CHARIN,SINI>
 00178 00079	DSCR STRING SIMPLE PROCEDURE SINI(INTEGER JFN,MAXLENGTH,BRKCHAR)
 00182 00080	Input 
 00188 00081	 BACKUP, DOINP TO BACKUP JFN, DO INPUT. 
 00199 00082	Realin, Realscan 
 00201 00083	Intin, Intscan 
 00203 00084	DSCR NUMIN
 00206 00085	NUMIN -- CONTD.
 00210 00086	SCAN (CALLED BY NUMIN AND STRIN)
 00214 00087	   Character table for SCAN (Realscan,Intscan,Realin,Intin)
 00216 00088	DSCR DATA TABLES FOR REALIN, INTSCAN, ETC.
 00217 00089	COMPIL(STDBRK,<STDBRK>,<SAVE,RESTR,GOGTAB,X22>
 00218 00090	
 00219 00091	
 00220 00092	
 00221 ENDMK
⊗;
TENX<;THE ENTIRE FILE IS FOR TENEX ONLY
COMMENT ⊗ TENEX-IOSER -- R. SMITH ⊗
	LSTON	(IOSER)


IFN ALWAYS, <BEGIN IOSER>

COMMENT ⊗ INDICES, BITS FOR TENEX VERSION OF IOSER ⊗


;WORDS IN CDB BLOCK FOR EACH CHANNEL


?GFL←←0				;FLAGS FOR GTJFN
?OFL←←1				;FLAGS FOR OPENF
?BRCHAR←←2			;BRCHAR ADDRESS
?ICOUNT←←3			;COUNT ADDRESS
?ENDFL←←4			;EOF ADDRESS
?ICOWNT←←5			;INPUT COUNT
?IBP←←6				;INPUT BYTE-POINTER
?OCNT←←7			;OUTPUT COUNT
?OBP←←10			;OUTPUT BYTE-POINTER
?DVTYP←←11				;DEVICE TYPE
?DVDSG←←12			;DEVICE DESIGNATOR
?OPNDUN←←13			;TRUE IF OPENED WITH THE OPEN STATEMENT
?DVCH←←14			;DEVICE CHARACTERISTICS
?DMPED←←15			;TRUE IF DUMP MODE OUTPUT SEEN
				;IN PARTICULAR USED TO NOTE IF A MAGTAPE
				;HAS BEEN WRITTEN BUT NOT YET CLOSED,
				;SINCE EOF'S ARE WRITTEN AT THE CLOSE
				;BY CLOSF,CFILE,CLOSE,ETC.
?LINNUM←←16			;LINE NO (FOR INPUT FUNCTION)
?PAGNUM←←17			;PAGE NO (FOR INPUT FUNCTION)
?SOSNUM←←20			;SOS LINE NO (FOR INPUT FUNCTION)
?DECCLZ←←21		;TRUE IF DEC-STYLE CLOSE JUST SEEN

?IOTLEN←←22			;CURRENT LENGTH OF CDB BLOCK

IFNDEF JFNSIZE, <?JFNSIZE←←20>			;NUMBER OF CHANNELS ALLOWED
?DMOCNT←←200			;(DEFAULT) COUNT FOR DUMP MODE OUTPUT
IFNDEF STARTPAGE,<?STARTPAGE←←610			;STARTING PAGE FOR BUFFERS>

;BITS FOR SCAN FLAGS FOR OPENFILE ROUTINE
;THE BITS OF THE FLAGS WORD ARE THE SAME AS THE BITS OF GTJFN AND OPENF
;HOPEFULLY (WHERE APPLICABLE)

?STARBIT←←1B11			;B11 OF GTJFN FOR INDEXED FILES
?TEMBIT←←1B5			;B5 OF GTJFN FOR TEMPORARY FILE
?DELBIT←←1B8			;GTJFN -- IGNORE DELETED BIT
?RDBIT←←1B19			;B19 OF OPENF FOR READING
?WRBIT←←1B20			;B20 OF OPENF FOR WRITING
?APPBIT←←1B22			;B22 OF OPENF FOR APPEND
?CONFB1←←1B3			;GTJFN BIT TO PRINT [CONFIRM] ETC
?CONFB2←←1B4			;GTJFN BIT TO REQUIRE CONFIRMATION FROM USER
				;ODDLY ENOUGH 3 AND 4 ARE ILLEGAL
?OUTBIT←←1B0			;GTJFN -- FILE FOR OUTPUT USE
?OLDBIT←←1B2			;GTJFN -- OLD FILE
?NEWBIT←←1B1			;GTJFN -- NEW FILE
?ERTNBIT←←1B27			;ERROR RETURN BIT -- INTERNAL
?BINBIT←←1B26			;BINARY BIT -- INTERNAL
?THAWBIT←←1B25			;THAWBIT GTJFN
?ERSNBIT←←1B28			;ERROR SEEN -- INTERNAL
?CONFBIT←←1B29			;CONFIRMATION -- INTERNAL

;MACROS FOR BIT TESTING

DEFINE .ZZZ $ (X,Y,Z)<
IFN Z&777777000000, <TL$X Y,Z⊗-=18>	;Z LSH -=18
IFN Z&777777, <TR$X Y,Z>
>

DEFINE TESTE (Y,Z) <.ZZZ NE,Y,Z>	;TDNE Y,[Z]
DEFINE TESTN (Y,Z) <.ZZZ NN,Y,Z>	;TDNN Y,[Z]
DEFINE TESTO (Y,Z) <.ZZZ O,Y,Z>		;TDO Y,[Z]
DEFINE TESTZ (Y,W) <.ZZZ Z,Y,W>		;TDZ Y,[Z]


;MACRO TO GET THE JFN NUMBER IN X FROM Y.  IF INVALID, JUMP TO LABEL Z
;LOADS CDB (I.E., 11) WITH THE CDB ADDRESS
;LOADS CHNL WITH THE CHANNEL NUMBER
DEFINE VALCHN(X,Y,Z) <

	SKIPL	CHNL,Y
	CAIL	CHNL,JFNSIZE
	  JRST	Z	
	MOVE	CDB,CDBTBL(CHNL)
	HRRZ	X,JFNTBL(CHNL)
	JUMPE	X,Z
>
	
;ONLY USES AC X
DEFINE VALCH1(X,Y,Z) <
	SKIPL	X,Y
	CAIL	X,JFNSIZE
	   JRST	Z
	HRRZ	X,JFNTBL(X)
	JUMPE	X,Z
>

;TTY STUFF
;CHAR FOR LINE DELETION (DELLINE) AND CHARACTER DELETION (RUBCHAR)
IFNDEF DELLINE,<?DELLINE←←"U"-100>	;CTRL-U	
IFNDEF RUBCHAR,<?RUBCHAR←←177>		;RUBOUT
?ALTMODE←←175			;ONE OF MANY VERSIONS OF ALTMODE


COMPIL(PAT,<OPEN,LOOKUP,ENTER,USETI,USETO,MTAPE,TENXFI,RELEASE,CLOSE,CLOSIN,CLOSO,GETCHAN,CVJFN,RENAME>
	,<SAVE,RESTR,RELEASE,CORGET,INSET>
	,<PAT -- TENEX ROUTINES EMULATING DEC CALLS>)

	BEGIN PAT

DSCR	PROCEDURE OPEN(INTEGER CHAN; STRING DEV; INTEGER MODE,IBUF,OBUF;
	REFERENCE INTEGER COUNT,BR,EOF)
⊗
HERE(OPEN)
	BEGIN OPEN
GTFLAGS←←4
OPFLAGS←←5
	PUSH	P,-7(P)
	PUSH	P,[0]				;CLOSE INHIBIT
	PUSHJ	P,RELEASE			;RELEASE IF ALREADY OPEN

;SEE WHAT KIND OF DEVICE WE HAVE

	PUSH	SP,-1(SP)
	PUSH	SP,-1(SP)
	PUSH	P,[0]
	PUSHJ	P,CATCHR		;PUT ON A NULL CHAR
	PUSHJ	P,MAKUP			;MAKE UPPER CASE (DAMMIT)
	PUSH	SP,-3(SP)
	PUSH	SP,-3(SP)
	PUSH	SP,[3]
	PUSH	SP,[POINT 7,[ASCIZ/:
/]]
	PUSHJ	P,CAT			;PUT ON A STRING
	POP	SP,-4(SP)
	POP	SP,-4(SP)		;SAVE ABOVE

	PUSHJ	P,SAVE			;NOW SAVE ACS
	SETZ	LPSA,			;NO PARAMETERS TO REMOVE
	MOVE	CHNL,-7(P)			;USER CHANNEL NUMBER
	MOVE	1,(SP)			;STRING FOR DEVICE	
	SUB	SP,X22			;ADJUST STACK
	JSYS STDEV
	   JRST BADOPN			;NOT A PLAUSIBLE DEVICE
	PUSH	P,2			;SAVE DEVICE DESIGNATOR
;ITS A PLAUSIBLE DEVICE
	MOVEI	C,IOTLEN
	PUSHJ	P,CORGET
	  ERR <OPEN:  CANNOT GET CORE>
	MOVE	CDB,B			;IO BLOCK ADDRESS
	MOVEM	CDB,CDBTBL(CHNL)	;SAVE 
;ZERO OUT CORE (SINCE CORGET DOESNT!!!)
	HRL	B,B
	ADDI	B,1
	SETZM	(CDB)
	BLT	B,IOTLEN-1(CDB)		

	POP	P,1			;GET DEVICE DESIGNATOR
	MOVEM	1,DVDSG(CDB)		;AND SAVE IT
	JSYS DVCHR
	MOVEM	2,DVCH(CDB)		;SAVE DEVICE CHARACTERISTICS
	HLRZ	1,2			
	ANDI	1,777			;DEVICE TYPE
	MOVEM	1,DVTYP(CDB)		;SAVE IT
	TLNN	2,100000		;IS DEVICE A DIRECTORY DEVICE	
	   JRST	GTNOW			;NOPE, DO GTJFN AND OPENF NO
HASDIR:
;GET THE MODE IN 4
	MOVE	4,-6(P)			;MODE
	ANDI	4,17			;FORGET OTHER JUNK
;IF DEVICE IS A DECTAPE IN DUMP MODE THEN DO IT NOW ALSO
	CAIE	1,3			;IS IT A DECTAPE?
	  JRST	HASDI1			;NO	
	CAIN	4,17			;IN DUMP MODE?		
	  JRST	DOMNT			;YES MOUNT AND THEN OPEN
;SO DONT DO GTJFN NOW, BUT WAIT
HASDI1:	SETZM	JFNTBL(CHNL)		;BE SURE
	MOVEM	4,GFL(CDB)		;SAVE THE MODE AS THE GTJFN FLAGS
	HRL	4,-5(P)			;INPUT BUFFERS
	HRR	4,-4(P)			;OUTPUT BUFFERS	
	MOVEM	4,OFL(CDB)		;SAVE AS THE OPENF FLAGS
	JRST	GUDRET			;AND RETURN

;MOUNT AND OPEN DECTAPE IN DUMP MODE
DOMNT:	MOVE	A,DVDSG(CDB)		;GET DEVICE DESIGNATOR
	TLO	A,(1B3)			;DONT READ DIRECTORY FOR DUMP MODE
	JSYS MOUNT
	   JRST	BADOPN			;CANNOT MOUNT
	MOVSI	GTFLAGS,100001
	MOVE	1,GTFLAGS
	MOVE	2,(SP)
	JSYS GTJFN
	   JRST	BADOPN
	MOVEM	1,JFNTBL(CHNL)
	MOVEM	GTFLAGS,GFL(CDB)
	MOVE	OPFLAGS,[447400000000!RDBIT!WRBIT]
	MOVE	2,OPFLAGS
	JSYS OPENF
	   JRST	CNTOPN
	JRST	OPOK

GTNOW:	
	MOVSI	GTFLAGS,100001
	MOVE	1,GTFLAGS
	MOVE	2,(SP)			;DEVICE STRING
	JSYS GTJFN	
	   JRST	BADOPN			;NOPE CANNOT GET
	MOVEM	1,JFNTBL(CHNL)		;SAVE JFN
	MOVEM	GTFLAGS,GFL(CDB)	;AND SAVE THEM
;COMPUTE OPENF FLAGS
	SETZ	OPFLAGS,
	MOVE	2,DVCH(CDB)		;DEVICE CHARACTERISTICS
	TESTE	2,<1B1>			;CAN DO INPUT?
	   TESTO  OPFLAGS,RDBIT
	TESTE	2,<1B0>			;CAN DO OUTPUT?
	   TESTO  OPFLAGS,WRBIT
	MOVE	1,DVTYP(CDB)		;CHECK DEVICE TYPE
	CAIN	1,12			;IS IT A TTY?
	   JRST	OP7BT			;USE 7 BIT BYTES
;NOW TRY VARIOUS THINGS, LOOKING FOR SOMETHING THAT WORKS

	HRRZ	1,JFNTBL(CHNL)
	HRLI	OPFLAGS,440000
	MOVE	2,OPFLAGS		;36-BIT, MODE 0
	JSYS OPENF	
	   SKIPA
	JRST	OPOK	
	HRRZ	1,JFNTBL(CHNL)
	HRLI	OPFLAGS,447400		;36-BIT, MODE 17
	MOVE	2,OPFLAGS
	JSYS OPENF
	  SKIPA
	JRST 	OPOK
OP7BT:	HRRZ	1,JFNTBL(CHNL)
	HRLI	OPFLAGS,70000		;7-BIT, MODE 0
	MOVE	2,OPFLAGS
	JSYS OPENF
	   JRST NOOPN
OPOK:	MOVEM	OPFLAGS,OFL(CDB)	;SAVE OP FLAGS
GUDRET:	
;SAVE FLAGS
	SETOM	OPNDUN(CDB)		;INDICATE OPENED WITH OPEN
	POP	P,TEMP			;RETURN ADDRESS
	POP	P,ENDFL(CDB)		;SAVE GOOD THINGS
	POP	P,BRCHAR(CDB)
	POP	P,ICOUNT(CDB)		
	SETZM	@ENDFL(CDB)		;INDICATE GOOD OPENING
	SUB	SP,X22			;CLEAN UP STACKS
	SUB	P,X44
	JRST	RESTR			;AND RETURN
	

NOOPN:
CNTOPN:	SKIPN	1,JFNTBL(CHNL)		;RELEASE JFN
	JSYS RLJFN
	  JFCL
BADOPN:
	SKIPE	B,CDBTBL(CHNL)		;CORE ALLOCATED?
	  PUSHJ	P,CORREL		;RELEASE CORE
	SETZM	JFNTBL(CHNL)
	SETZM	CDBTBL(CHNL)
	SKIPN	@-1(P)			;USER WANTS ERROR?
	  ERR	<OPEN:  IO ERROR OR ILLEGAL SPECIFICATIONS>,1
	SETOM	@-1(P)
	POP	P,TEMP
	SUB	P,[XWD 7,7]
	SUB	SP,X22	
	JRST	RESTR




	BEND OPEN

;MAKE UPPER CASE LETTERS
MAKUP:	PUSHJ	P,SAVE
	SKIPE	SGLIGN(USER)
	  PUSHJ	P,INSET
	HRRZ	A,-1(SP)		;LENGTH OF STRING	
	ADDM	A,REMCHR(USER)
	SKIPLE	REMCHR(USER)		;OK?
	  PUSHJ	P,STRNGC		;NO, COLLECT
	MOVE	B,A
	HRRO	A,A
	PUSH	SP,A
	PUSH	SP,TOPBYTE(USER)
UPPER1:	JUMPLE	B,UPPER2		;DONE YET?
	ILDB	C,-2(SP)		;NEXT CHAR
	CAIL	C,141		
	CAILE	C,172
	  SKIPA	
	SUBI	C,40			;CONVERT TO UPPER CASE
	IDPB	C,TOPBYTE(USER)
	SOJA	B,UPPER1	
UPPER2:	POP	SP,-2(SP)
	POP	SP,-2(SP)
	SETZ	LPSA,
	POP	P,TEMP			;RETURN ADDR
	JRST	RESTR			;RETURN

DSCR  PROCEDURE LOOKUP(INTEGER CHNL; STRING FILE; REFERENCE INTEGER FLAG)

⊗

HERE(LOOKUP)
	BEGIN	LOOKUP
	PUSHJ	P,TENXFI		;MAKE THE FILE SPEC TENEX

	PUSH	P,1
	PUSH	P,2
	PUSH	P,3
	PUSH	P,CHNL
	PUSH	P,CDB
	DEFINE CHNARG <-7(P)>
	DEFINE FLGARG <-6(P)>

	
	SKIPL	CHNL,CHNARG
	CAIL	CHNL,JFNSIZE	
	   JRST	BADLU1
	MOVE	CDB,CDBTBL(CHNL)
	SKIPN	OPNDUN(CDB)		;ERROR IF NOT OPENED
	   JRST	BADLU1
	MOVE	2,DVCH(CDB)		;GET DEVICE CHARACTERISTICS
	TLNN	2,100000		;DOES DEVICE HAVE A DIRECTORY?
	   JRST	LUKRET			;NO, NO LOOKUP
	SKIPE	JFNTBL(CHNL)		;JFN ALREADY ASSIGNED?
	   PUSHJ P,RELNOW		;YES, RELEASE IT

	PUSHJ	P,DEVCAT

	MOVSI	1,100001		;OLD FILE
	MOVE	2,(SP)
	JSYS GTJFN	
	   JRST	BADLUK
	MOVEM	1,JFNTBL(CHNL)
	MOVSI	3,100001
	MOVEM	3,GFL(CDB)
	MOVE	2,[XWD 440000,200000]	;36-BIT
	JSYS OPENF
	   SKIPA
	JRST 	GUDLUK
	MOVE	1,JFNTBL(CHNL)
	MOVE	2,[XWD 447400,200000]	;36-BIT, DUMP
	JSYS OPENF
	   SKIPA
	JRST	GUDLUK
	MOVE	1,JFNTBL(CHNL)
	MOVE	2,[XWD 70000,200000]	;7-BIT
	JSYS OPENF
	   JRST	BADLUK
GUDLUK:	MOVEM	2,OFL(CDB)
	SETZM	@FLGARG
LUKRET:	POP	P,CDB
	POP	P,CHNL
	POP	P,3
	POP	P,2
	POP	P,1
	SUB	SP,X22
	SUB	P,X33
	JRST	@3(P)

BADLUK:	MOVEM	1,@FLGARG
	JRST	LUKRET

BADLU1:	SETOM	@FLGARG		
	JRST	LUKRET


	BEND LOOKUP

DEVCAT:
;HERE WITH CDB LOADED, FILENAME ON THE SP STACK
;RETURN WITH "DEV:FILE" & 0 ON THE SP STACK
;MUST NOT HAVE CALLED SAVE WHEN THIS IS CALLED
	PUSH	P,1
	PUSH	P,2
	PUSH	P,[=100]
	PUSHJ	P,ZSETST		;BP IN 1
	MOVE	2,DVDSG(CDB)		;DEVICE DESIGNATOR
	JSYS	DEVST
	   ERR <LOOKUP, ENTER, OR RENAME:  CANNOT DO DEVST>
	PUSH	P,[=100]
	PUSH	P,1			;UPDATED BP
	PUSHJ	P,ZADJST
	PUSH	P,[":"]
	PUSHJ	P,CATCHR
	PUSHJ	P,CAT.RV		
	PUSH	P,[0]
	PUSHJ	P,CATCHR
	POP	P,2
	POP	P,1
	POPJ	P,

;RELEASE JFN ALREADY THERE
RELNOW:	
	PUSH	P,CHNL			;CHANNEL
	PUSHJ	P,CLOSF			;CLOSE DANCE
	PUSH	P,1
	MOVE	1,JFNTBL(CHNL)		;GET JFN	
	JSYS	RLJFN			;RELEASE
	  ERR <CANNOT RELEASE JFN>,1
	SETZM	JFNTBL(CHNL)		;AND ZERO OUT
	SETZM	DECCLZ(CDB)		;NO CLOSE DONE
	POP	P,1
	POPJ	P,

	
HERE(ENTER)
	BEGIN ENTER

	PUSHJ	P,TENXFI

	PUSH	P,1
	PUSH	P,2
	PUSH	P,3
	PUSH	P,CHNL
	PUSH	P,CDB
	DEFINE 	CHNARG <-7(P)>
	DEFINE	FLGARG <-6(P)>

	SKIPL	CHNL,CHNARG
	CAIL	CHNL,JFNSIZE
	   JRST	BADEN1
	MOVE	CDB,CDBTBL(CHNL)
	SKIPN	OPNDUN(CDB)
	   JRST	BADEN1			;WAS AN OPEN PERFORMED HERE?
	SKIPN	1,JFNTBL(CHNL)
	   JRST	NOTOPN
	MOVE	2,DVCH(CDB)		;GET DEVICE CHARACTERISTICS
	TLNN	2,100000		;DOES DEVICE HAVE DIRECTORY?
	   JRST	ENTRET			;NO

	SKIPE	DECCLZ(CDB)		;A DEC-STYLE CLOSE DONE?
	  JRST [PUSHJ P,RELNOW		;RELEASE JFN
		JRST NOTOPN		;AND PROCEED
	      ]
	PUSH	P,1			;SAVE JFN
	JSYS CLOSF
	   JFCL	;IGNORE
	POP	P,1
	MOVE	2,OFL(CDB)
	TESTO	2,WRBIT			;TURN ON WRITE BIT
	MOVEM	2,OFL(CDB)		;AND SAVE NEW FLAGS
	JSYS OPENF
	   JRST	BADENT			;ERROR IN 1	    
	JRST	ENTRET			;RETURN

NOTOPN:	
	PUSHJ	P,DEVCAT

	MOVSI	1,600001		;NEW FILE
	MOVE	2,(SP)
	JSYS GTJFN
	   JRST	BADENT			;CANNOT GTJFN
	MOVEM	1,JFNTBL(CHNL)
	MOVSI	2,600001		;THE 
	MOVEM	2,GFL(CDB)		;SAVE THE GTJFN FLAGS
B36:	HRRZ	1,JFNTBL(CHNL)
	MOVE	2,[XWD 440000,100000]	;36-BIT
	JSYS OPENF	
	   SKIPA
	JRST	ENT1	
	HRRZ	1,JFNTBL(CHNL)
	MOVE	2,[XWD 447400,100000]	;36-BIT, DUMP
	JSYS OPENF
	   SKIPA
	JRST	ENT1
	HRRZ	1,JFNTBL(CHNL)
	MOVE	2,[XWD 70000,100000]
	JSYS OPENF
	   JRST	BADENT
ENT1:	MOVEM	2,OFL(CDB)
ENTRET:	SETZM	@FLGARG
ENTPOP:	POP	P,CDB
	POP	P,CHNL
	POP	P,3
	POP	P,2
	POP	P,1
	SUB	SP,X22
	SUB	P,X33
	JRST	@3(P)


BADENT:	MOVEM	1,@FLGARG
	JRST	ENTPOP

BADEN1:	SETOM	@FLGARG
	JRST	ENTPOP

	BEND ENTER
	
DSCR
	RENAME(CHNL,"STR",PROT,@FLAG)
	Since protection is not implemented in TENEX,
the feature will be ignored.
⊗

HERE(RENAME)
	BEGIN RENAME
	PUSH	P,1
	PUSH	P,2
	PUSH	P,3
	PUSH	P,CHNL
	PUSH	P,CDB
	DEFINE CHNARG <-10(p)>
	DEFINE FLGARG <-6(P)>	

	VALCHN	1,CHNARG,RENBAD
	PUSHJ	P,OPNCHK		;MAKE SURE OPEN (SOMEWHAT REDUNDANT)
	MOVE	2,DVCH(CDB)		;DEVICE CHARS
	TLNN	2,100000		;DIRECTORY DEVICE?
	  JRST	RENRET			;NO, NOP
	
	PUSHJ	P,TENXFI		;MAKE A TENEX FILE NAME

;PERHAPS ONLY A DELETE?
	HRRZ	2,-1(SP)		;NULL FILE SPEC?
	JUMPE	2,RENDEL		;YES, DELETE 	

;ACTUALLY RENAME (ON THE SAME DEVICE)
	PUSH	P,CHNARG
	PUSHJ	P,CLOSF			;FIRST CLOSE THE FILE

	PUSHJ	P,DEVCAT

	MOVE	3,1			;SAVE FIRST JFN
	MOVE	1,GFL(CDB)		;USE SAME FLAGS
	TESTZ	1,OLDBIT		;EXCEPT NOT OLD
	TESTO	1,NEWBIT		;BUT DO WANT NEW
	TESTO	1,OUTBIT		;AND VERSION DEFAULTING
	MOVEM	1,GFL(CDB)		;SAVE FLAGS
	MOVE	2,(SP)
	JSYS GTJFN
	   JRST	RENERR			;ERROR BITS IN 1
	
	MOVE	2,1			;NEW JFN	
	MOVE	1,3			;OLD JFN
	JSYS RNAMF
	   JRST	RENERR			;ERROR BITS IN 1
	MOVE	1,2			;NEW JFN
	MOVE	2,OFL(CDB)		;OPENF FLAGS
	JSYS	OPENF
	   JRST	RENERR			;ERROR BITS IN 1
	MOVEM	1,JFNTBL(CHNL)		;SAVE THE NEW JFN

RENRET:	SETZM	@FLGARG			;INDICATE A GOOD RETURN
RENRE1:	POP	P,CDB
	POP	P,CHNL
	POP	P,3
	POP	P,2
	POP	P,1
	SUB	SP,X22
	SUB	P,X44
	JRST	@4(P)

RENERR:	MOVEM	1,@FLGARG
	JRST	RENRE1

RENBAD:	SETOM	@FLGARG
	JRST	RENRE1

RENDEL:	JSYS DELF				;JFN IN 1
	   JRST	RENERR
	JRST	RENRET
	BEND RENAME

DSCR PROCEDURE USETI,USETO(INTEGER CHANNEL,BLOCK)
⊗

HERE(USETI)
HERE(USETO)
	PUSHJ	P,SAVE
	MOVE	LPSA,X33
	VALCHN	1,-2(P),USETER
	PUSHJ	P,OPNCHK		;MAKE SURE OPEN
	MOVE	2,DVTYP(CDB)		
	CAIN	2,3			;IS IT A DECTAPE?
	   JRST	USEDTA			;YES
DOSFPT:	MOVE	2,-1(P)
	SUBI	2,1
	IMULI	2,200			;BLOCK NUMBER
	JSYS SFPTR
	   ERR <USETI OR USETO:  CANNOT DO SFPTR>,1
	JRST	RESTR

USEDTA:
;SFPTR DOES NOT SEEM TO WORK TO THE DECTAPE IN TENEX
;;;	LDB	2,[POINT 4,OFL(CDB),9]	;MODE
;;;	CAIE	2,17			;DUMP?
;;;	  JRST	DOSFPT			;NO	   

	MOVEI	2,30			;OPERATION 30 FOR DECTAPES
	HRRZ	3,-1(P)			;TAPE BLOCK
	JSYS MTOPR				;SET DIRECTLY
	JRST	RESTR			;AND RETURN
USETER: ERR<Illegal JFN>,1
	JRST	RESTR			;AND RETURN
		
DSCR	PROCEDURE CLOSE(INTEGER CHANNEL)
	PROCEDURE CLOSO(INTEGER CHANNEL)
	PROCEDURE CLOSIN(INTEGER CHANNEL)
⊗
	BEGIN CLOSES

HERE(CLOSIN)
HERE(CLOSO)
HERE(CLOSE)
DOOPN:	PUSH	P,-1(P)
	PUSHJ	P,CLOSF			;FORCE BUFFERS OUT, WRITE MAGT EOFS, CLOSF
	PUSHJ	P,SAVE
	VALCHN	1,-1(P),CLORET
	SETOM	DECCLZ(CDB)		;INDICATE DEC CLOSE PERFORMED
CLORET:	MOVE	LPSA,X22
	JRST	RESTR

	BEND CLOSES

HERE(RELEASE)
DSCR
	Ignores the close inhibit bits that are available in 
the STANFORD SAIL, until we decide what to do with them.
⊗

	PUSH	P,1
	PUSH	P,-3(P)		;CHANNEL
	PUSHJ	P,CFILE
	POP	P,1		;RESTORE 1
	SUB	P,X33
	JRST	@3(P)		;RETURN




DSCR	
	PROCEDURE MTAPE(INTEGER CHAN,OPERATION)
(the operation is a character e.g., "U" to unload)
as in the SAIL manual.
⊗

HERE(MTAPE)
	BEGIN MTAPE
	PUSHJ	P,SAVE
	MOVE	LPSA,X33
	LDB	C,[POINT 5,-1(P),35]
	MOVE	A,OPTAB
	MOVE	B,OPTAB+1
	TRZE	C,30			;COMPRESS TABLE
	ADDI	C,5	
	LSH	C,2
	ROTC	A,(C)
	ANDI	B,17
	VALCHN	1,-2(P),MTAERR
	PUSHJ	P,OPNCHK		;MAKE SURE OPEN
	JSYS MTOPR
	JRST	RESTR
MTAERR: ERR <Illegal JFN>,1
	JRST	RESTR

OPTAB:	BYTE (4) 16,17,0,0,3,6,7,13,10	;A,B,E,F,R,S,T
	BYTE (4) 11,0,1			;U,W

	BEND MTAPE

	


DSCR	STRING PROCEDURE TENXFI(STRING DECFILE)

	Converts the string to a TENEX file specification.
A la Alex Cannara.
⊗

HERE(TENXFI)
	BEGIN TENXFI

CTRLV←←"V"-100
FIND←←2

	PUSH	P,1
	PUSH	P,2
	PUSH	P,3
	SETZM	FIND
	PUSH	SP,[0]		;DEVICE TEMPORARY
	PUSH	SP,[0]
	PUSH	SP,[0]		;DIR TEMPORARY
	PUSH	SP,[0]
	PUSH	SP,[0]		;NAM TEMPORARY
	PUSH	SP,[0]	

DEFINE ORIG <-7(SP)>
DEFINE ORIG1 <-6(SP)>
DEFINE DEV <-5(SP)>
DEFINE DEV1 <-4(SP)>
DEFINE DIR <-3(SP)>
DEFINE DIR1 <-2(SP)>
DEFINE NAM <-1(SP)>
DEFINE NAM1 <0(SP)>

;SIMPLE SINCE NAME IS AT THE TOP OF SP
DEFINE CATNAM (X) <
	PUSH	P,X
	PUSHJ	P,CATCHR
>
DEFINE CATDIR (X) <
	PUSH	P,X
	PUSH	SP,DIR
	PUSH	SP,DIR
	PUSHJ	P,CATCHR
	POP	SP,-4(SP)
	POP	SP,-4(SP)
>

DEFINE GCH <
	HRRZ	1,ORIG
	JUMPE	1,TENDUN
	ILDB	3,ORIG1
	SOS	ORIG
>


TENX1:	GCH
	CAIE	3,CTRLV
	  JRST	NOQUOTE
	SKIPE	FIND
	  JRST	QUODIR
	PUSHJ	P,CATNA3
	GCH	
	PUSHJ	P,CATNA3 		;AND THE CHAR FOLLOWING THE CTRLV	
	JRST	TENX1
QUODIR:	PUSHJ	P,CATDI3
	GCH
	PUSHJ	P,CATDI3
	JRST	TENX1			;AND CONTINUE

NOQUOTE:
	CAIN	3,":"			;COLON -- DEVICE
	   JRST	ISDEV			;ITS BEEN A DEVICE ALL ALONG!!
	CAIN	3,","
	   JRST	TENX1			;IGNORE COMMA
	CAIE	3,40			;SPACE
	CAIN	3,11			;OR TAB
	   JRST	TENX1

	CAIE	3,"<"			;THESE START THE DIRECTORY NAME
	CAIN	3,"["
	   JRST	STDIR
	CAIE	3,">"			;THESE FINISH THE DIR. NAME
	CAIN	3,"]"
	   JRST	ENDDIR
	SKIPE	FIND			;DOING DIRECTORY?
	   JRST	.+3			;YES
	PUSHJ	P,CATNA3
	JRST	TENX1
	PUSHJ	P,CATDI3
	JRST	TENX1

STDIR:	SETOM	FIND
	SKIPE	DIR			;ANYTHING THERE?
	   JRST	TENX1			;YES, IGNORE
	CATDIR	<[74]>
	JRST	TENX1

ENDDIR:	SETZM	FIND
	JRST	TENX1

ISDEV:	PUSHJ	P,CATNA3		;PUT THE COLON ON THE NAME
	MOVE	3,NAM			;THE "NAME" HAS REALLY BEEN A DEV
	MOVEM	3,DEV
	MOVE	3,NAM1
	MOVEM	3,DEV1			
	
	SETZM	NAM			;SO CLEAR THE NAME -- START OVER
	SETZM	NAM1
	JRST	TENX1

TENDUN:	
;CHECK TO SEE WHAT LAST CHAR OF DIR IS
	SKIPN	DIR
	  JRST	GOTDIR			;NO DIRECTORY THERE
	CATDIR	<[76]>			;PUT ON A ">"
;NOW STACK HAS ORIG,DEV,DIR,NAM
GOTDIR: 
	PUSHJ	P,CAT
;NOW STACK HAS ORIG,DEV,<DIR>NAM
	PUSHJ	P,CAT
;NOW STACK HAS ORIG,DEV:<DIR>NAM
GOTDI1:	POP	SP,-2(SP)
	POP	SP,-2(SP)

TXFRET:
	POP	P,3
	POP	P,2
	POP	P,1
	POPJ	P,


;CALL CAT MACROS WITH AC 3 AS THE ARG
CATNA3:	CATNAM 3
	POPJ	P,

CATDI3:	CATDIR 3
	POPJ	P,


	BEND TENXFI

DSCR
	INTEGER PROCEDURE GETCHAN(INTEGER I)
RETURNS AN UNUSED CHANNEL NUMBER, AND MARKS IT
FOR USE, SO THAT NO ONE WILL TRY TO USE IT.
⊗

HERE(GETCHAN)
	MOVE	A,[XWD -JFNSIZE+1,1]		;START AT CHANNEL 1
GETCH1:	SKIPN	CDBTBL(A)	;ALLOCATED YET?
	   JRST	GETCH2		;NO, TAKE IT
	AOBJN A,GETCH1	;YES
	SETOM	A		;INDICATE ERROR 
	POPJ	P,

GETCH2:	HRRZ	A,A
	PUSH	P,B		;NOW ALLOCATE A TABLE
	PUSH	P,C
	MOVEI	C,IOTLEN
	PUSHJ	P,CORGET
	  ERR <GETCHAN:  CANNOT GET CORE>
	MOVEM	B,CDBTBL(A)

	HRL	C,B		;ZERO OUT BLOCK
	HRRI	C,1(B)
	SETZM	(B)
	BLT	C,IOTLEN-1(B)
		
	SETZM	JFNTBL(A)	;BUT NO JFN (YET)
	POP	P,C
	POP	P,B
	POPJ	P,

DSCR
	INTEGER PROCEDURE CVJFN(INTEGER CHAN)

	Returns the JFN (XWD flags,jfn)  associated
with a logical channel, -1 if no jfn assigned.
	Hereby, the user of these routines can access
the system directly if the need arises.
⊗
HERE(CVJFN)
	SKIPL	1,-1(P)
	CAIL	1,JFNSIZE
	  JRST 	CVJFER
	SKIPN	1,JFNTBL(1)
	  JRST	CVJFER
CVJFR:	SUB	P,X22
	JRST	@2(P)
CVJFER:	SETO	1,
	JRST	CVJFR


BEND PAT

ENDCOM(PAT)

COMPIL(JOBINF,<ODTIM,IDTIM,RUNTM,GTAD,GJINF>,<ZSETST,ZADJST,X22,X33,X44,.SKIP.,CATCHR>
	,<JOBINF -- JOB UTILITY ROUTINES>)
DSCR STRING SIMPLE PROCEDURE ODTIM(INTEGER DT,FORMAT)
	Returns the string representation of DT
(which is in internal TENEX representation).  If DT
is -1 the current date and time are used.  If format
is -1, the standard format is used.
⊗
HERE(ODTIM)
	PUSH	P,[=100]	; 100 CHARS
	PUSHJ	P,ZSETST	;GET BP IN 1
	MOVE 2,-2(P)		;TIME
	MOVE 3,-1(P)		;FORMAT
	JSYS ODTIM
	PUSH	P,[=100]
	PUSH	P,1		;UPDATED BP
	PUSHJ	P,ZADJST	;GET STRING
	SUB	P,X33		;ADJUST STACK
	JRST	@3(P)		;RETURN

DSCR INTEGER SIMPLE PROCEDURE IDTIM(STRING S)
	Returns the internal TENEX representation of S, which
is assumed to be the date and time in some reasonable format.
If the format cannot be scanned, the error is returned in .SKIP.

⊗

HERE(IDTIM)
	PUSH	P,[0]
	PUSHJ	P,CATCHR		
	MOVE 	1,(SP)			;BYTE-POINTER
	SETZB 	2,.SKIP.		;NO SPECIAL FORMAT, ASSUME NO ERROR
	JSYS IDTIM
	MOVEM 	1,.SKIP.		;ERROR TO USER
	MOVE  	1,2			;ANSWER
	SUB	SP,X22			;ADJUST SP STACK
	POPJ	P,			;RETURN
DSCR INTEGER SIMPLE PROCEDURE RUNTM(INTEGER FORK; REFERENCE INTEGER CONSOLE);
	Returns the runtime of a fork.  If FORK=-5, then then
whole job.  Time is returned as milliseconds for you.  Console time,
similarly converted, is returned in CONSOLE.
⊗
HERE(RUNTM)
	MOVE 	1,-2(P)
	JSYS RUNTM
	MOVEM 	3,@-1(P)
	SUB	P,X33	
	JRST	@3(P)
DSCR INTEGER SIMPLE PROCEDURE GTAD;
	Returns the current date and time.  See Jsys manual,
3-3.
⊗
HERE(GTAD)
	JSYS GTAD
	POPJ P,
DSCR INTEGER SIMPLE PROCEDURE GJINF(REFERENCE INTEGER LOGDIR,CONDIR,TTYNO);
	Returns the TENEX jobnumber.  LOGDIR is the directory 
no. logged in, CONDIR is the connected directory number.  TTYNO is the
TENEX teletype number, which is -1 if the job is detached.  
	See the DIRST routine for converting directory numbers to 
directory strings.
⊗

HERE(GJINF)
	JSYS GJINF
	MOVEM 	1,@-3(P)
	MOVEM 	2,@-2(P)
	MOVEM 	4,@-1(P)
	MOVE 	1,3;
	SUB	P,X44
	JRST	@4(P)
ENDCOM(JOBINF)

COMPIL(DIRECT,<STDIR,DIRST>,<X22,X33,CATCHR,ZSETST,ZADJST.SKIP.>
	,<DIRECT -- TENEX DIRECTORY SPECS>)
DSCR INTEGER SIMPLE PROCEDURE STDIR(STRING S; BOOLEAN DORECOGNITION)
DESR
	Returns the directory number associated with a string.
Any problems are returned in .SKIP. with the code:
		1 string does not match
		2 string is ambiguous.
⊗
HERE(STDIR)
	PUSH	P,[0]
	PUSHJ	P,CATCHR	;TACK ON 0
	SETZ 	3,		;
	MOVEI 	1,1 		; ASSUME NO RECOGNITION
	SKIPE 	-1(P)		; DO WE WANT IT?
	SETO  	1,		; YES AFTER ALL
	MOVE 	2,(SP)		;BYTE-POINTER
	JSYS STDIR
	MOVEI 	3,1		; NO MATCH;
	MOVEI 	3,2 		; AMBIGUOUS
	MOVEM 	3,.SKIP.	; SAVE IT FOR USER
	HRRZ 	1,1 		; SAVE DIR NO. (ONLY)
	SUB	SP,X22		;ADJUST STRING STACK
	SUB	P,X22
	JRST	@2(P)		;RETURN	
	
DSCR STRING SIMPLE PROCEDURE DIRST(INTEGER I)
	Returns the string name for directory I.  Any problems
cause .SKIP. to be set TRUE.
⊗

HERE(DIRST)
	PUSH	P,[=100]
	PUSHJ	P,ZSETST
	SETZM 	.SKIP.
	MOVE 	2,-1(P)		;DIRECTORY NO.
	JSYS DIRST
	SETOM 	.SKIP.
	PUSH	P,[=100]
	PUSH	P,1		;UPDATED BP
	PUSHJ	P,ZADJST	;GET STRING ON STACK
	SUB	P,X22		
	JRST	@2(P)

ENDCOM(DIRECT)
COMPIL(RUNPRG,<RUNPRG>,<X22,X33,CATCHR>,<RUNPRG -- RUN A PROGRAM>)
DSCR INTEGER SIMPLE PROCEDURE RUNPRG(STRING PROGRAM; INTEGER INCREM; BOOLEAN NEWFORK)
	This does two entirely different things depending on whether
NEWFORK is true or not.
	If NEWFORK then a new fork is created, capabilities transmitted,
and PROGRAM is run there.  INCREM is added to the entry vector.  Any problems
cause the routine to return FALSE, otherwise it returns TRUE.
	If not NEWFORK then the current job is destroyed and replaced
with PROGRAM, with INCREM added to the entry vector location.  This is
like the DEC RUN uuo, and hence if the increment is 1, the program is
started at the CCL address.  If the routine returns at all, there was a problem
with the file.
	Remember to say .SAV as the PROGRAM extension.
⊗


HERE(RUNPRG)
	BEGIN 
	JFN←←0
	FORK←←14
	PUSH	P,[0]
	PUSHJ	P,CATCHR	
	MOVSI	1,100001 	; OLD FILE, PTR IN 2	
	MOVE	2,(SP) 		; STRING POINTER
	JSYS GTJFN 			; TRY FOR JFN		
	   JRST RUNERR 		; ERROR
	MOVEM	1,JFN 		; SAVE JFN		

	SKIPN	-1(P) 		; USER WANTS FORK?
	   JRST SWP 		; NO, REPLACE CURRENT PRG

	MOVSI	1,100000 	; XMIT CAPABILITIES
	JSYS CFORK
	   JRST RUNERR 	; CANNOT CREATE FORK
	MOVEM	1,FORK 	; SAVE HANDLE
	SETOB	2,3 	; INDICATE ALL PRIVILEDGES
	JSYS EPCAP
	HRLZ	1,1 	; FORK HANDLE
	HRR	1,JFN 	; THE JFN
	JSYS GET 		; JSYS GET THE FILE
	MOVEI	1,400000 	; CURRENT FORK
	JSYS	GPJFN	;PRIMARY JFNS IN 2
	MOVE	1,FORK 	; SET PRIMARY IO	
	JSYS SPJFN	;FOR NEW FORK
	MOVE	1,FORK 	; FORK
	MOVE	2,-2(P) 	; USER VALUE FOR ENTRY VECTOR
	JSYS SFRKV	;START THE FORK
	MOVE	1,FORK ;
	JSYS WFORK
	SKIPE	1,FORK 	; SET TO KILL
	JSYS KFORK	;KILL THE FORK
	HRRZ	1,JFN ;
	JSYS RLJFN 		; RELEASE
	JFCL 		; IGNORE	
	JRST 	RUNRET 		; AND RETURN SAFELY

SWP:	
IMSSS,<				;DESTROY EMULATOR INFO AT IMSSS
	SETO	1,
	MOVE	2,[XWD 400000,711]	;PAGE 711
	JSYS	PMAP			;DESTROY
>;IMSSS
	PUSH	P,JFN			;SAVE THE JFN
	HRLI	A1 			; BLT INTO ACS
	HRRI	1 ;
	BLT	15 		; THE INSTRUCTIONS -- NOTE THAT RF IS NOW CLOBBERED
	POP	P,0		; RESTORE JFN TO AC0
	HRLI	0,400000 	; XWD FORK, JFN
 	MOVE	16,-2(P) 	; THE INCREMENT -- NOTE THAT SP IS NOW CLOBBERED
	MOVE	17,[254000400010] 	; FOR COMPARISON -- NOTE THAT THE P STACK IS GONE
	JRST	4 		; AND GO
A1:	-1 		; FOR PMAP
A2:	400000000677 	; THIS FORK, START AT 677 (LEAVING EMULATOR)
A3:	0 ;
A4:	JSYS PMAP
A5:	SOJL	2,4 	; LOOP THROUGH PAGES
A6:	MOVE	1,0 	; XWD 400000,JFN
A7:	JSYS GET ;
A10:	MOVEI	1,400000 	; THIS FORK
A11:	JSYS GEVEC 		; JSYS GET ENTRY VECTOR
A12:	CAMN	2,17 	; DEC STYLE??
A13:	  HRRZ	2,120 	; YES
A14:	ADD	2,16 	; ADD THE INCREMREMENT
A15:	JRST	(2) 	; AND START THE JOB

RUNERR:	TDZA	1,[-1]	;ZERO 1 AND SKIP
RUNRET:	SETO	1,	;INDICATE SUCCESS
	SUB	SP,X22
	SUB	P,X33
	JRST	@3(P)


	BEND;RUNPRG
ENDCOM(RUNPRG)
COMPIL(OPF,<OPENFILE,SETINPUT,SETPL,INDEXFILE>,<.SKIP.>,<OPENFILE -- OPEN A FILE>)
DSCR INTEGER SIMPLE PROCEDURE OPENFILE(STRING NAME,OPTIONS)

	Name is the name of the file to be opened.  If it is null, then
OPENFILE goes to the user's console for the filname (with recognition).
	The value of the call is the jfn returned to the user.
	OPTIONS is a string of options available to the user.  Legal 
characters are:

One of these:
	R		read
	W		write
	A		append
Version numbering
	O		old file
	N		new file
	T		temporary file
	*		index with INDEXFILE routine

Independent:
	C		require confirmation
	D		ignore deleted bit
	H		"thawed" access
Error handling
	E		return errors to user in the external
			integer !skip!.  TENEX error codes are used.
			(JFN will be released in this case.)
	OPENFILE does a GTJFN followed by a OPENF.  If GTJFN fails, a new
attempt is made, from the user's console.  
⊗

	BEGIN OPENFILE
JFN←3				;WHERE TO PUT THINGS
FLAGS←4
GTFLAGS←5
OPFLAGS←6

DEFINE EQ $ (X,Y) <
	CAIE	A,"$X$"
	   JRST .+3
	TESTO	FLAGS,Y
	JRST	OPCONT
>

DEFINE JTRUE $ (X) <
	TESTN	FLAGS,X
>
DEFINE JFALSE (X) <
	TESTE	FLAGS,X
>

DEFINE 	SGT (X) <
	TESTO	GTFLAGS,X
>
DEFINE  SOF (X) <
	TESTO	OPFLAGS,X
>
DEFINE  TGT (X) <
	TESTE	FLAGS,X
	  TESTO GTFLAGS,X
>
DEFINE  TOP (X) <
	TESTE	FLAGS,X
	  TESTO OPFLAGS,X
>

HERE(OPENFILE)
	SETZB	FLAGS,.SKIP.
	SETZB	GTFLAGS,OPFLAGS
	HRRZ	B,-1(SP)		;COUNT OF OPTIONS WORD

WHIOPT:	JUMPE	B,OPTDUN
	ILDB	A,(SP)			;GET AN OPTION
	CAIGE	A,141
	   JRST .+3
	CAIG	A,172
	   SUBI	A,40			;CONVERT TO UPPER CASE
;ANY NON-ALPHABETIC CHARS GO HERE

	EQ 	*,STARBIT
;NOW ALLOW ONLY ALPHABETIC CHARS
	CAIL	A,101			;MUST BE 
	CAILE	A,132
	   JRST	OPTERR
	SKIPN	BITTBL-"A"(A)		;SOMETHING THERE?
	   JRST	OPTERR			;NOPE, ERROR
	TDO	FLAGS,BITTBL-"A"(A)	;RIGHT SPOT IN TABLE
	SOJGE	B,WHIOPT
	  JRST	OPTDUN
;HERE ON ERROR
OPTERR:	ERR	<OPENFILE:  ILLEGAL OPTION >,1
	TESTO	FLAGS,ERSNBIT

  OPCONT:
	SOJGE	B,WHIOPT

;NOW SET UP GTFLAGS ACCORDING TO THE SCANNED INFORMATION
OPTDUN:		
	TGT	OLDBIT			;INSIST ON OLD?
	TGT	NEWBIT			;INSIST ON NEW?
	JTRUE	OLDBIT
	JFALSE	NEWBIT			;IF NEITHER
	  JRST	OPTDU1			;WELL, ONE
	JTRUE	WRBIT			;IF WRITING
	  JRST	OPTDU1
	JFALSE	RDBIT			;AND READING
	JTRUE	APPBIT			;BUT NOT APPENDING
	  SGT	OUTBIT			;THEN SET OUTPUT BIT
OPTDU1:
;NOW TEST FOR INDEPENDANT THINGS
	TOP	RDBIT
	TOP	WRBIT
	TOP	APPBIT
	TGT	TEMBIT
	TGT	STARBIT
	TOP	THAWBIT
	JFALSE	CONFBIT
	   JRST	[SGT	CONFB1
		 SGT	CONFB2
		 JRST	.+1]
	TLO	GTFLAGS,1		;SHORT CALL OF GTJFN
GTAGAIN:
	HRRZ	A,-3(SP)		;LENGTH OF NAME
	JUMPE	A,[TRYAGN:  
		   TLO	GTFLAGS,2
		   MOVE	2,[XWD 100,101]
		   JRST  GT]
	AND 	GTFLAGS,[717777777777]
	
	PUSH	SP,-3(SP)
	PUSH	SP,-3(SP)
	PUSH	P,[0]
	PUSHJ	P,CATCHR		;CONCATENATE A NULL CHAR
	MOVE	2,(SP)			;BYTE-POINTER
	SUB	SP,X22			;ADJUST STACK
GT:	MOVE	1,GTFLAGS
	JSYS GTJFN
	  JRST 	GTERR
	MOVEM	1,JFN			;REMEMBER JFN
	PUSHJ	P,SETCHN		;SET A CHANNEL, ALLOCATE, GET CDB, SET DVTYP, RETURN CHANNEL
	MOVEM	1,CHNL			;REMEMBER CHANNEL	
	MOVEM	GTFLAGS,GFL(CDB)


COMMENT ⊗ Do the open.
⊗
	MOVE	1,DVTYP(CDB)		;CHECK THE DEVICE TYPE
	CAIN	1,12			;IS IT A TTY?
	   JRST	B7			;YES, USE 7 BIT
B36:	HRRZ	1,JFN			;JFN
	HRRZ	2,OPFLAGS
	HRLI	2,440000		;36-BIT, MODE 0
	JSYS OPENF	
	   JRST	B36DMP			;TRY 36-BIT, DUMP MODE
	JRST	OPNOK
B36DMP:	HRRZ	1,JFN
	HRRZ	2,OPFLAGS
	HRLI	2,447400		;36 BITS, DUMP MODE
	JSYS OPENF			
	   JRST	B7
	JRST	OPNOK
B7:	HRRZ	1,JFN
	HRRZ	2,OPFLAGS
	HRLI	2,70000			;7 BIT
	JSYS OPENF
	    JRST OPERR			;NOPE
OPNOK:	MOVEM	2,OFL(CDB)		;SAVE 
	MOVE	1,CHNL			;RETURN CHANNEL NO	
OPFRET:	SUB	SP,X44			;ADJUST
	POPJ	P,			;AND RETURN




GTERR:
;HERE WITH ERROR ON GTJFN
	JTRUE	ERTNBIT			;USER WANT'S ERRORS?
	   JRST	GTER1			;NO
ERRRET:	MOVEM	1,.SKIP.		;STORE FOR USER
	SETO	1,			;SOMETHING SUSPICIOUS
	JRST	OPFRET			;AND RETURN

GTER1:	HRROI	1,[ASCIZ/
CANNOT GTJFN FILE /]
	JSYS PSOUT
	PUSH	SP,-3(SP)
	PUSH	SP,-3(SP)
	PUSHJ	P,OUTSTR
	HRROI	1,[ASCIZ/, TRY AGAIN  */]
	JSYS PSOUT
	JRST	TRYAGN



OPERR:	JTRUE	ERTNBIT
	   JRST	OPER1
	PUSH	P,1			;SAVE ERROR BITS
	PUSH	P,CHNL
	PUSHJ	P,CFILE			
	POP	P,1			;RESTORE ERROR BITS
	JRST	ERRRET

OPER1:	HRROI	1,[ASCIZ/
CANNOT OPENF FILE /]
	JSYS 	PSOUT
	PUSH	SP,-3(SP)
	PUSH	SP,-3(SP)
	PUSHJ	P,OUTSTR
	HRROI	1,[ASCIZ/, TRY AGAIN  */]
	JSYS 	PSOUT	
	PUSH	P,CHNL			;CLOSE AND RELEASE FILE AND CDB BLOCK
	PUSHJ	P,CFILE
	JRST	TRYAGN	

BITTBL: APPBIT	;A
	BINBIT	;B
	CONFBIT	;C
	DELBIT	;D
	ERTNBIT	;E
	0	;F
	0	;G
	THAWBIT	;H
	0	;I
	0	;J
	0	;K
	0	;L
	0	;M
	NEWBIT	;N
	OLDBIT	;O
	0	;P
	0	;Q
	RDBIT	;R
	0	;S
	TEMBIT	;T
	0	;U
	0	;V
	WRBIT	;W
	0	;X
	0	;Y
	0	;Z


	BEND OPENFILE

DSCR PROCEDURE SETINPUT(INTEGER CHAN; REFERENCE INTEGER COUNT,BR,EOF)
	Sets up the variables associated with input (as in the DEC
open statement.)
⊗

HERE(SETINPUT)
	PUSHJ	P,SAVE
	VALCHN	1,-4(P),SETERR
	POP	P,TEMP
	POP	P,ENDFL(CDB)
	SKIPE	ENDFL(CDB)
	   SETZM @ENDFL(CDB)		;ASSUME NOT EOF
	POP	P,BRCHAR(CDB)
	SKIPE	BRCHAR(CDB)
	   SETZM @BRCHAR(CDB)		;ASSUME NO BRCHAR
	POP	P,ICOUNT(CDB)
	SETZ	LPSA,			;NO PARAMETERS
	SUB	P,X11
	JRST	RESTR
SETERR: ERR <Illegal JFN>,1
	MOVE	LPSA,[XWD 5,5]
	JRST	RESTR

DSCR
	SETPL(CHAN,@LINNUM,@PAGNUM,@SOSNUM)

	Names the variables to be used by the INPUT
function for counting the line-feeds (12), formfeeds (14)
seen by INPUT, as well as keeping the current SOS line
number, if any.  Useful when scanning a file, and
you want to know what page,line you are on.
	Initializes all three variables to 0.

⊗
HERE(SETPL)
	PUSHJ	P,SAVE
	VALCHN	1,-4(P),SETPER
	POP	P,TEMP		;RET ADR
	POP	P,SOSNUM(CDB)
	SETZM	@SOSNUM(CDB)
	POP	P,PAGNUM(CDB)
	SETZM	@PAGNUM(CDB)
	POP	P,LINNUM(CDB)
	SETZM	@LINNUM(CDB)
	SUB	P,X11		;REMOVE CHANNEL NO.
SETRET:	SETZ	LPSA,
	JRST	RESTR
SETPER: ERR <Illegal JFN>,1
	MOVE	LPSA,[XWD 5,5]
	JRST	RESTR




DSCR
	BOOLEAN PROCEDURE INDEXFILE(INTEGER JFN)

RETURNS TRUE AS LONG AS WE CAN GNJFN ANOTHER FILE
⊗

HERE(INDEXFILE)
	PUSH	P,-1(P)
	PUSHJ	P,CLOSF
	PUSH	P,-1(P)
	PUSHJ	P,GNJFN
	JUMPE	1,INDRET		;RETURN FALSE IF NO OTHER FILES
	PUSH	P,2
	PUSH	P,CDB
	PUSH	P,CHNL		
;CHANNEL ALREADY VALID
	MOVE	CHNL,-4(P)			;CHANNEL NUMBER
	MOVE	CDB,CDBTBL(CHNL)		;CDB LOC
	HRRZ	1,JFNTBL(CHNL)		;JFN
	MOVE	2,OFL(CDB)		;GET OPENFLAGS
	JSYS OPENF			;TRY OPENING
	  JRST NOIND
	SKIPE	ENDFL(CDB)		;ZERO SETINPUT (or OPEN) VARIABLES IF HERE
	  SETZM	@ENDFL(CDB)
	SKIPE	BRCHAR(CDB)
	  SETZM	@BRCHAR(CDB)
	SKIPE	LINNUM(CDB)		;ZERO SETPL VARS
	  SETZM	@LINNUM(CDB)
	SKIPE	PAGNUM(CDB)
	  SETZM	@PAGNUM(CDB)
	SKIPE	SOSNUM(CDB)
	  SETZM	@SOSNUM(CDB)
	SETO	1,
INDPOP:	POP	P,CHNL
	POP	P,CDB
	POP	P,2
INDRET:	SUB	P,X22	
	JRST	@2(P)

NOIND:	ERR <INDEXFILE:  CANNOT OPENF>,1
	SETZ	1,
	JRST	INDPOP




ENDCOM(OPF)
COMPIL(GTJFN,<GTJFN,GTJFNL>,<.SKIP.,SETCHN,CATCHR,X11,X22,X44>,<GTJFN -- GET A JFN>)
DSCR INTEGER SIMPLE PROCEDURE GTJFN(STRING S; INTEGER FLAGS)
	Does a GTJFN.  If S is non-null, it is the filename, otherwise
the routine goes to the user's console for a file.  FLAGS are used for
accumulator 1, and any error code is returned in .SKIP.  The value
of the call is the JFN, if obtained.
	Defaults for FLAGS:  0  means ordinary input, 1 means ordinary
output.  Ordinarily the user will use the OPENFI routine.
⊗

HERE(GTJFN)
	SKIPN 	1,-1(P)
	   MOVSI 1,100001
	CAIN	1,1
	   MOVSI 1,600001	
	TLO	1,1			;MARK FOR SHORT CALL
	HRRZ	2,-1(SP)
	JUMPE	2,[MOVE 2,[100000101]
		  TLO	1,2		;INDICATE XWD JFN,JFN IN 2
		   JRST GOTDEST]
	TLZ	1,2			;INDICATE BYTE-POINTER IN 2
	PUSH	P,[0]			
	PUSHJ	P,CATCHR		;PUT ON A NULL
	MOVE	2,(SP)
GOTDEST: SETZM	.SKIP.			;ASSUME NO ERROR
	PUSH	P,1			;SAVE FLAGS
	JSYS GTJFN
	  JRST GTBAD 		; SOMETHING IS WRONG
	PUSHJ	P,SETCHN	;SETUP A CHANNEL, AND ALLOCATE, GET STATUS, SET CDB
	POP	P,GFL(CDB)	;SAVE FLAGS
GTRET:	SUB	SP,X22
	SUB	P,X22
	JRST	@2(P)

GTBAD:
	
	MOVEM 	1,.SKIP.		; REMEMBER
	POP	P,1			;ADJUST STACK
	SETO 	1, 		; SOMETHING SUSPICIOUS TO RETURN TO USER
	JRST	GTRET

DSCR INTEGER PROCEDURE GTJFNL(STRING ORIG; INTEGER FLAGS, XWDJFN!JFN;
	STRING DEV,DIR,NAM,EXT,PROT,ACCOUNT; INTEGER DESIRED!JFN)

	Does the long form of GTJFN.  
⊗
HERE(GTJFNL)
	BEGIN GTJFNL

DEFINE STRPUT(X)<
	PUSHJ	P,.STPUT
	MOVEM	A,X
>
DEFINE FLG <-14(P)>
DEFINE IOJFN <-13(P)>
DEFINE DESJFN <-12(P)>
	ADD	P,[XWD 11,11]		;ROOM FOR LONG-FORM TABLE
	TLNN	P,400000		;OVERFLOW?
	  ERR	<GTJFNL:  P-stack overflow>
	MOVE	A,DESJFN	
	MOVEM	A,0(P)			;THE DESIRED JFN
	STRPUT	-1(P)			;ACCOUNT
	STRPUT	-2(P)			;PROTECTION
	STRPUT	-3(P)			;EXTENSION
	STRPUT	-4(P)			;NAME
	STRPUT	-5(P)			;DIRECTORY
	STRPUT	-6(P)			;DEVICE
	MOVE	A,IOJFN			;XWD INPUT JFN, OUTPUT JFN
	MOVEM	A,-7(P)
	MOVE	A,FLG	
	MOVEM	A,-10(P)
	STRPUT	B			;MAIN STRING POINTER
	MOVEI	A,-10(P)		;ADDRESS OF BLOCK (ON STACK)
	SETZM	.SKIP.			;ASSUME NO ERROR
	JSYS	GTJFN			;LONG FORM
	   JRST	GTLBAD			;NOPE
	PUSHJ	P,SETCHN		;SET UP CHANNEL TABLE, ALLOCATE, GET STATUS, SET CDB
	MOVE	B,-10(P)		;GTJFN FLAGS
	MOVEM	B,GFL(CDB)		;SAVE
GTLRET:	SUB	P,[XWD 11+4,11+4]	;ADJUST STACK FOR LONG-FORM TABLE, AND ARGUMENTS
	JRST	@4(P)			;AND RETURN

GTLBAD:	MOVEM	A,.SKIP.		;RETURN ERROR CODE TO USER
	SETO	A,			;SOMETHING SUSPICIOUS
	JRST	GTLRET			;AND RETURN

.STPUT:	HRRZ	A,-1(SP)		;GET THE COUNT
	  JUMPE	A,[SUB	SP,X22		;ADJUST AND RETURN
		   POPJ	P,]
	PUSH	P,[0]
	PUSHJ	P,CATCHR
	POP	SP,A
	SUB	SP,X11
	POPJ	P,


	BEND GTJFNL



ENDCOM(GTJFN)
COMPIL(FILINF,<GNJFN,DELF,UNDELETE,SIZEF,JFNS,OPENF,CFILE,CLOSF,RLJFN,GTSTS,STSTS,RNAMF>
	,<JFNTBL,CDBTBL,STRSND,X11,X22,X33,CORREL,.SKIP.,ZSETST,ZADJST>
	,<FILINF -- UTILITY FILE ROUTINES>)


DSCR INTEGER SIMPLE PROCEDURE GNJFN(INTEGER JFN)
	Does the GNJFN jsys.
⊗
HERE(GNJFN)
	PUSHJ	P,SAVE
	MOVE	LPSA,X22
	VALCHN 1,<-1(P)>,GNERR
	MOVE	1,JFNTBL(CHNL)		;GET THE WHOLE JFN
	SETO	2,;			;ASSUME GOOD
	JSYS GNJFN
	SETZ 	2,			;NOPE, BAD
	MOVEM	2,RACS+A(USER)
	JUMPE	2,GNRLZ			;RELEASE IF NO OTHER FILE
GNRET:	JRST	RESTR

GNERR:  ERR <Illegal JFN>,1
	SETZM	RACS+A(USER)
	JRST	RESTR

GNRLZ:	PUSH	P,-1(P)
	PUSHJ	P,CFILE
	JRST	RESTR

DSCR	PROCEDURE DELF(INTEGER CHAN)
	Deletes file open on CHAN.  Errors to .SKIP. 
⊗
HERE(DELF)
	PUSH	P,1
	VALCH1	1,-2(P),DELF1
	JSYS	DELF
	  JRST	DELF2
	SETZM	.SKIP.			;NO ERROR
DELFRE:	POP	P,1
	SUB	P,X22
	JRST	@2(P)
DELF1:	SETO	1,
DELF2:	MOVEM	1,.SKIP.
	JRST	DELFRE

DSCR	PROCEDURE UNDELETE(INTEGER CHAN)
	Undeletes file open on CHAN.  Errors to .SKIP.
⊗
HERE(UNDELETE)
	PUSHJ	P,SAVE
	VALCH1	1,-1(P),UNDEL1
	HRLI	1,1			;XWD 1,JFN
	MOVSI	2,(1B3)			;DELETED BIT
	SETZ	3,			;TURN IT OFF
	JSYS	CHFDB			;CHANGE THE FDB
	JRST	RESTR
UNDEL1:	SETOM	.SKIP.
	JRST	RESTR
	



DSCR	INTEGER PROCEDURE SIZEF(INTEGER JFN)
	Gets the size in pages of the file open on JFN, with error code to 
.SKIP.
⊗
HERE(SIZEF)
	PUSHJ	P,SAVE
	MOVE	LPSA,X22
	VALCHN 1,<-1(P)>,SIZERR
	SETZM	.SKIP.
	JSYS SIZEF
	JRST [MOVEM 1,.SKIP.
		SETZM	RACS+A(USER)
		JRST SIZRET]
	MOVEM	3,RACS+A(USER)		;ANSWER IN AC 3
SIZRET:	JRST	RESTR

SIZERR: ERR <Illegal JFN>
	SETOM	.SKIP.
	JRST	SIZRET



DSCR STRING SIMPLE PROCEDURE JFNS(INTEGER JFN,FLAGS)
	Returns the name of the file associated with JFN.
FLAGS are for ac 3 as described in the jsys manual, with
0 the reasonable default.
⊗

HERE(JFNS)
	VALCHN	2,<-2(P)>,JFNSER	;GET JFN IN AC2
	PUSH	P,[=100]
	PUSHJ	P,ZSETST		;GET BP IN AC 1
	MOVE	3,-1(P)
	JSYS JFNS
	PUSH	P,[=100]
	PUSH	P,1
	PUSHJ	P,ZADJST
JFNSRE:	SUB	P,X33
	JRST	@3(P)
JFNSER: ERR <Illegal JFN>,1
	PUSH	SP,[0]			;RETURN NULL STRING
	PUSH	SP,[0]
	JRST	JFNSRE

DSCR SIMPLE PROCEDURE OPENF(INTEGER JFN,FLAGS)
	Does an OPENF.

PARAMETERS:
	JFN     the JFN
	FLAGS 	for accumulator 2.
	.SKIP.	the error code (if pertinent)

Some defaults:
	FLAGS		ACTION
	-----------------------
	0		INPUT CHARACTERS
	1		OUTPUT CHARACTERS
	2		INPUT 36-BIT WORDS
	3		OUTPUT 36-BIT WORDS
	4		DUMP MODE INPUT (USE DUMPI FUNCTION)
	5		DUMP MODE OUTPUT (USE DUMPO FUNCTION)
	VALUES 6-10 ARE RESERVED FOR EXPANSION

Other values of FLAGS are interpreted literally.
	Ordinarily the user will use the OPENFI routine.
⊗

HERE(OPENF)
	PUSHJ	P,SAVE
	MOVE	LPSA,X33
	VALCHN	1,-2(P),OPNERR
	SKIPL	2,-1(P)		;GET THE FLAGS
	CAILE	2,5		;CHECK IN RANGE 0-5
	   JRST	GOTFLAGS
	MOVE	2,OPNTBL(2)	;GET CORRECT WORD
GOTFLAGS:
	SETZM	.SKIP.
	PUSH	P,2		;SAVE FLAGS
	JSYS OPENF
	  JRST	NOOPN
	POP     P,OFL(CDB)	;AND SAVE FLAGS
OPNRET:	JRST	RESTR

OPNERR: ERR <Illegal JFN>,1
	SETOM	.SKIP.
	JRST	OPNRET

NOOPN:	MOVEM	1,.SKIP.
	SUB	P,X11		;ADJUST STACK
	JRST	OPNRET

OPNTBL:	070000200000		;7-BIT READ
	070000100000		;7-BIT WRITE
	440000200000		;36-BIT READ
	440000100000		;36-BIT WRITE
	447400200000		;36-BIT DUMP READ
	447400100000		;36-BIT DUMP WRITE


DSCR SIMPLE INTEGER PROCEDURE CFILE(INTEGER JFN)
	Closes the file (CLOSF) and releases (RLFJN)
the jfn.  This is the ordinary way the user will use
to dispense with a file.
	Returns TRUE if JFN legal and released, FALSE o.w.
Always returns.
⊗

HERE(CFILE)
	PUSH	P,2
	PUSH	P,3
	PUSH	P,CHNL
	PUSH	P,CDB
	SKIPL	CHNL,-5(P)
	CAIL	CHNL,JFNSIZE
	   JRST	CFBAD
	MOVE	CDB,CDBTBL(CHNL)	;GET CDB
	SKIPN	1,JFNTBL(CHNL)	;JFN ASSIGNED?
	   JRST	CFBA1		;NO, JUST RELEASE CORE
	HRRZ	1,1		;JFN ONLY
	LDB	2,[POINT 6,OFL(CDB),5]		;GET BYTE SIZE
	CAIE	2,=36		;36-BIT?
	   JRST RLCOR		;NO
;FILE IN 36-BIT BYTES
	SKIPE	OBP(CDB)	; A BYTE-POINTER?
	  PUSHJ	P,STRSND	;SEND OUT THE BUFFER
	PUSHJ	P,CUNMAP	;UNMAP THE PAGE
	SKIPN	DMPED(CDB)	;DUMP-MODE OUTPUT SEEN?
	  JRST	RLCOR		;NO
	PUSHJ	P,MTCHK		;CHECK FOR MAGTAPE OUTPUT
	SETZM	DMPED(CDB)	;AND INDICATE ALL DONE

RLCOR:	SKIPE	B,CDBTBL(CHNL)	; ANY CORE TO RELEASE?
	  PUSHJ	P,CORREL	; RELEASE THE BLOCK
	TLZ	1,400000	; BE SURE TO RELEASE
	JSYS CLOSF		; CLOSE (AND RELEASE)
	   JFCL			; ERROR RETURN
	HRRZ	1,JFNTBL(CHNL)	; GET JFN AGAIN
	JSYS	RLJFN		; RELEASE (FOR GOOD MEASURE IF FILE NOT OPEN)
	   JFCL			; ERROR RETURN
	SETO	1, 		; RETURN TRUE FOR GOOD RELEASE
      	SETZM	CDBTBL(CHNL)
	SETZM	JFNTBL(CHNL)
CFRET:	POP	P,CDB
	POP	P,CHNL
	POP	P,3
	POP	P,2
	SUB	P,X22 		; ADJUST
	JRST	@2(P) 		; RETURN

CFBAD:	SETZ	1, 		; RETURN FALSE
	JRST	CFRET ;

CFBA1:	SKIPE	B,CDB
	PUSHJ	P,CORREL	;RELEASE CORE BLOCK
	SETZM	CDBTBL(CHNL)	;REMOVE ALL TRACE
	SETZM	JFNTBL(CHNL)	
	SETZ	1,		; RETURN FALSE
	JRST	CFRET

;HERE WITH 1,CHNL,CDB LOADED
;IF DEVICE IS MAGTAPE, THEN WRITE TWO EOF'S AND BACKSPACE
MTCHK:
	PUSH	P,2		;SAVE 2
	MOVE	2,DVTYP(CDB)	;GET DEVICE TYPE
	CAIE	2,2		;IS IT A MAGTAPE?
	  JRST	MTRET		;NO
	MOVEI	2,3		;WRITE EOF
	JSYS MTOPR
	JSYS MTOPR
	MOVEI	2,17		;NOW BACKSPACE
	JSYS MTOPR
MTRET:	POP	P,2		;RESTORE
	POPJ	P,

;HERE WITH 1,CHNL,CDB LOADED
;UNMAP PAGE ASSOCIATED WITH JFN
;CLOBBERS 2,3
CUNMAP:
	PUSH	P,1		;SAVE JFN
	MOVEI	2,STARTPAGE(1)
	HRLI	2,400000	;XWD THIS FORK, PAGE NO.
	SETO	1,
	SETZ	3,
	JSYS	PMAP
	POP	P,1		;GET JFN BACK
	POPJ	P,



DSCR SIMPLE PROCEDURE CLOSF(INTEGER JFN)
	Does a CLOSF on the JFN.  Ordinarily the user
will want to use the CFILE routine, which handles errors
internally. The CLOSF is accomplished in such a way that
the JFN is actually not released.
	If the device is a magtape open for output, then
2 eof's are written, followed by a backspace.  This writes
a standard end-of-file on the tape.
⊗
HERE(CLOSF)
	PUSHJ	P,SAVE
	MOVE	LPSA,X22
	VALCHN	1,<-1(P)>,CLOERR
	LDB	2,[POINT 6,OFL(CDB),5]	;BYTE-SIZE
	CAIE	2,=36		;36-BIT BYTES?
	   JRST	DOCLO
;RELEASE BUFFER IN CORE (IF THERE IS ONE)
	SKIPE	OBP(CDB)	;A BYTE POINTER?
	  PUSHJ	P,STRSND	;CLEAN UP BUFFER IN CORE
	PUSHJ	P,CUNMAP	;UNMAP THE PAGE
	SKIPE	DMPED(CDB)	;DUMP-MODE IO SEEN?
	  PUSHJ	P,MTCHK		;CHECK IF MAGT-TAPE (AND MARK EOF,EOF)
	SETZM	DMPED(CDB)	;AND INDICATE ALL DONE
	SETZM	ICOWNT(CDB)
	SETZM	IBP(CDB)
	SETZM	OCNT(CDB)
	SETZM	OBP(CDB)
	SETZM	DECCLZ(CDB)

DOCLO:	SETZM 	.SKIP.		;ASSUME NO ERROR
	TLO 1,400000 		; DO NOT RELEASE THE JFN
	JSYS CLOSF
	  MOVEM	1,.SKIP.	;ERROR
CLORET:	JRST	RESTR

CLOERR:	
	SETOM	.SKIP.
	JRST	CLORET





DSCR SIMPLE PROCEDURE RLJFN(INTEGER JFN)
	Does the RLJFN jsys.  Ordinarily the user will want
to use the CFILE routine, which handles errors internally.
⊗

HERE(RLJFN)
	PUSHJ	P,SAVE
	MOVE	LPSA,X22
	SKIPL	C,-1(P)
	CAIL	C,JFNSIZE
	   JRST	RLJBAD
	SKIPN	1,JFNTBL(C)
 	   JRST	RLJBAD
	SETZM	JFNTBL(C)	
	SKIPE	B,CDBTBL(C)
	PUSHJ	P,CORREL
	SETZM	CDBTBL(C)
	SETZM	.SKIP.		;ASSUME NO ERROR
	JSYS RLJFN
	  MOVEM	1,.SKIP.	;ERROR RETURN
RLJRET:	JRST	RESTR

RLJBAD: ERR <Illegal JFN>,1
	SETOM 	.SKIP.
	JRST	RLJRET


DSCR INTEGER SIMPLE PROCEDURE GTSTS(INTEGER JFN);
	Gets the file status. 
	WARNING: The results of this call are not necessarily appropriate
if the file is open in special character input mode.  If you want to check
for end-of-file, examine the EOF variable instead.
⊗

HERE(GTSTS)
	PUSHJ	P,SAVE
	MOVE	LPSA,X22
	VALCHN	1,<-1(P)>,GTSERR
	JSYS GTSTS
	MOVEM	2,RACS+A(USER)
GTSRET:	JRST	RESTR

GTSERR:	ERR <Illegal JFN>,1
	JRST	GTSRET
DSCR BOOLEAN SIMPLE PROCEDURE STSTS(INTEGER JFN,STATUS);
	Sets the status of JFN to STATUS using the STSTS jsys.
⊗

HERE(STSTS)
	VALCH1 	1,<-2(P)>,STSERR
	MOVE	2,-1(P)
	SETO	3,			;ASSUME	SKIP
	SETZM	.SKIP.
	JSYS	STSTS
	  JRST [STERRT: SETZ	3,			;PROBLEM	
		MOVEM	1,.SKIP.
		JRST .+1]
	MOVE	1,3			;RETURN
	SUB	P,X33
	JRST	@3(P)

STSERR:	ERR <Illegal JFN>,1
	JRST	STERRT			;RETURN

DSCR BOOLEAN SIMPLE PROCEDURE RNAMF(INTEGER EXISTINGJFN,NEWJFN);
	File open on EXISTINGJFN is renamed to file open
on NEWJFN.
⊗
HERE(RNAMF)
	VALCH1	1,<-2(P)>,RNFERR
	VALCH1	2,<-1(P)>,RNFERR
	SETO	3,			;ASSUME OK
	SETZM	.SKIP.
	JSYS	RNAMF
	   JRST [RNERET:  SETZ	3,
		 MOVEM	1,.SKIP.
		 JRST	.+1]
RNFRET:	MOVE	1,3			;RETURN VALUE
	SUB	P,X33
	JRST	@3(P)

RNFERR:	ERR <Illegal JFN>,1
	JRST	RNERET

ENDCOM(FILINF)	
COMPIL(DEVINF,<CNDIR,ASND,RELD,GDSTS,SDSTS,STDEV,DEVST>
	,<JFNTBL,CDBTBL,STRSND,X11,X22,X33,CORREL,.SKIP.,ZSETST,ZADJST>
	,<DEVINF -- DEVICE AND DIRECTORY ROUTINES>)

DSCR BOOLEAN SIMPLE PROCEDURE CNDIR(INTEGER DIR; STRING PASSWORD);
	Using the CNDIR jsys, connects to TENEX directory DIR (for
AC1.)  PASSWORD is the password, which will usually be null, as
in the EXEC CONNECT command.
⊗

HERE(CNDIR)
	PUSH	P,[0]
	PUSHJ	P,CATCHR		;PUT A NULL ON THE END OF THE PASSWORD
	POP	SP,2			;GET BP IN 2
	SUB	SP,X11			;CLEAN UP SP STACK
	MOVE	1,-1(P)			;DIRECTORY NO 
	SETO	3,			;ASSUME SUCCESS
	SETZM	.SKIP.
	JSYS	CNDIR
	  JRST	[SETZ 3,
		 MOVEM	1,.SKIP.
		 JRST	.+1]
	MOVE	1,3
	SUB	P,X22
	JRST	@2(P)

DSCR BOOLEAN PROCEDURE ASND(INTEGER DEVICE)
	Assigns the device specified by DEVICE using the ASND jsys.
Returns TRUE if successful, else error code in .SKIP.
⊗	

HERE(ASND)
	MOVE	1,-1(P)			;GET DEVICE DESIGNATOR
	JSYS	ASND
	  JRST	[MOVEM 1,.SKIP.
		 SETZ	1,
		 JRST .+2]
	SETO	1,
	SUB	P,X22
	JRST	@2(P)
DSCR BOOLEAN PROCEDURE RELD(INTEGER DEVICE)
	Releases DEVICE using the RELD jsys.  If DEVICE is -1,
then releases all devices assigned to this job.
⊗
	
HERE(RELD)
	MOVE	1,-1(P)
	JSYS	RELD
	  JRST	[MOVEM	1,.SKIP.
		 SETZ	1,
		 JRST	.+2]
	SETO	1,
	SUB	P,X22
	JRST	@2(P)
DSCR INTEGER SIMPLE PROCEDURE GDSTS(INTEGER CHAN; REFERENCE INTEGER WORDCNT)
	Returns the device status of device open on CHAN using the GDSTS
jsys.  The LH of WORDCNT has the word count of the last transfer completed,
negative if the last transfer completed unsuccessful.
⊗

HERE(GDSTS)
	VALCH1	1,<-2(P)>,GDSERR
	SETZM	.SKIP.
	JSYS	GDSTS
	MOVEM	3,@-1(P)			;REFERENCE ARG
	MOVE	1,2				;RETURN VALUE
GDSRET:	SUB	P,X33
	JRST	@3(P)
GDSERR:	ERR <Illegal JFN>,1
	SETOM	.SKIP.	
	SETZ	1,		
	JRST	GDSRET
DSCR PROCEDURE SDSTS(INTEGER JFN,NEWSTATUS)
⊗
HERE(SDSTS)
	VALCH1	1,<-2(P)>,SDSERR
	SETZM	.SKIP.				;INDICATE NO ERROR
	MOVE	2,-1(P)
	JSYS	SDSTS
SDSRET:	SUB	P,X33
	JRST	@3(P)
SDSERR:	ERR	<Illegal JFN>,1
	SETOM	.SKIP.
	JRST	SDSRET
DSCR INTEGER PROCEDURE STDEV(STRING S)
	S is a string pointer to a string of the form DTA1.
The device designator is returned.
⊗

HERE(STDEV)
	PUSH	P,[0]
	PUSHJ	P,CATCHR
	POP	SP,1
	SUB	SP,X11			;CLEAN SP STACK
	SETZM	.SKIP.
	JSYS	STDEV
	  JRST	[MOVEM 2,.SKIP.
		 SETZ	1,
		 JRST .+2]
	MOVE	1,2
	POPJ	P,


DSCR STRING PROCEDURE DEVST(INTEGER DEVICE)
⊗
HERE(DEVST)
	PUSH	P,[=100]
	PUSHJ	P,ZSETST		;GET A BP FOR 100 CHARS
	SETZM	.SKIP.
	MOVE	2,-1(P)
	JSYS	DEVST
	  MOVEM	2,.SKIP.		;INDICATE ERROR
	PUSH	P,[=100]
	PUSH	P,1			;UPDATED BP
	PUSHJ	P,ZADJST
	SUB	P,X22
	JRST	@2(P)
	

ENDCOM(DEVINF)
COMPIL(FIO,<OUT,CHAROUT,LINOUT,GTFDB>
	,<CDBTBL,JFNTBL,X22,X33,X44,.SKIP.,SAVE,RESTR>
	,<FILIO -- IO ROUTINES>)

DSCR SIMPLE PROCEDURE CHAROUT(INTEGER JFN; INTEGER JFN)
⊗
HERE(CHAROUT)
	BEGIN CHAROUT

	PUSH	P,1
	PUSH	P,2
	PUSH	P,CDB
	PUSH	P,CHNL
	SKIPL	CHNL,-6(P)			;CHANNEL
	CAIL	CHNL,JFNSIZE
	   JRST	CHOLIT			;USE JFN LITERALLY
	MOVE	CDB,CDBTBL(CHNL)
	HRRZ	1,JFNTBL(CHNL)
	SKIPN	1
	   JRST	CHAOBAD
	LDB	2,[POINT 6,OFL(CDB),5]	;GET BYTE SIZE			
	CAIN	2,=36
	   JRST B36
	PUSHJ	P,OPNCHK
	MOVE	2,-5(P)
	JSYS BOUT
	JRST	CHARET

B36:	MOVE	2,-5(P)
	SOSGE	OCNT(CDB)	
	   PUSHJ P,STRSN0		;WITH 1,CDB,CHNL LOADED
	IDPB	2,OBP(CDB)
CHARET:	POP	P,CHNL
	POP	P,CDB
	POP	P,2
	POP	P,1
	SUB	P,X33
	JRST	@3(P)

CHAOBAD: ERR <CHAROUT:  Illegal JFN OR BYTE-SIZE>,1
	JRST	CHARET

CHOLIT:	MOVE	1,-6(P)
	MOVE	2,-5(P)
	JSYS	BOUT
	JRST	CHARET

	BEND CHAROUT



DSCR SIMPLE PROCEDURE OUT(INTEGER JFN; STRING S)
	Outputs a SAIL string to the JFN, which may be open
in DUMP mode.
⊗
HERE(OUT)
	BEGIN OUT
	PUSHJ	P,SAVE
	MOVE	LPSA,X22
	HRRZ 3,-1(SP) 		; GET THE COUNT
	JUMPE 3,SOURET 		; DONT SEND NULL STRING
	VALCHN	1,-1(P),SOUBAD
	LDB	2,[POINT 6,OFL(CDB),5]	;GET BYTE SIZE
	CAIN	2,7		;7-BIT?
	   JRST	USESOU		;USE SOUT
	CAIE	2,=36		;36-BIT?
	   JRST SOUBAD

;HERE TO DO BUFFERED OUTPUT
DMPAGN:	ILDB	2,(SP)		;GET A CHARACTER
	SOSGE	OCNT(CDB)	;AND DECREMENT BUFFER COUNT
	  PUSHJ	P,STRSN0	;SO SEND THE BUFFER	;WITH 1,CDB,CHNL LOADED
	IDPB	2,OBP(CDB)	;AND COPY THE CHARACTER
	SOJG	3,DMPAGN	;STRING CHAR COUNT
SOURET:	SUB	SP,X22
	JRST	RESTR

	
USESOU:	PUSHJ	P,OPNCHK	;CHECK IF OPEN
	MOVE 2,(SP) 	; GET THE BYTE-POINTER
	MOVN 3,3 		; NEGATE BYTE-COUNT
	JSYS SOUT
	JRST	SOURET	
	
SOUBAD:	ERR <OUT Illegal JFN OR BYTE-SIZE>,1
	JRST 	SOURET

	BEND OUT

DSCR	PROCEDURE LINOUT(INTEGER JFN,VALUE)
⊗

HERE(LINOUT)
	BEGIN LINOUT

	PUSHJ	P,SAVE
	VALCHN	A,-2(P),LINBAD
	LDB	B,[POINT 6,OFL(CDB),5]	;GET BYTE-SIZE
	CAIE	B,=36		;MUST BE 36-BIT
	   JRST	LINBAD
	SKIPG	B,OCNT(CDB)	;ANY CHARS WAITING?
	   PUSHJ P,STRSND	;NO, SEND (OR PERHAPS JUST INITIALIZE)
	MOVE	TEMP,OBP(CDB)	;GET BP

LINOPL:	TLNN	TEMP,760000	;LINED BP?
	   JRST	OKLIGN
	IBP	TEMP
	SOJA	B,LINOPL	

OKLIGN:	MOVEM	TEMP,OBP(CDB)
	MOVEM	B,OCNT(CDB)
	CAIGE	B,=10		;ENOUGH FOR 10 CHARS?
	  PUSHJ	P,STRSND	;NO
	SKIPGE	B,-1(P)		;GET LINE-NO
	  JRST	[MOVNS B
		 MOVNI A,5
		 JRST	NOCONV]
	MOVNI	A,6
	MOVE	C,[<ASCII /00000/>/2]	
	EXCH	B,C
	PUSH	P,LNBAK
LNCONV:	IDIVI 	C,=10
	IORI	D,"0"
	DPB	D,[POINT 7,(P),6]
	SKIPE	C
	PUSHJ	P,LNCONV	;THE RECURSIVE PRINTER
	HLL	C,(P)
	LSHC	B,7
LNBAK:	POPJ	P,.+1
	LSH	B,1
	TRO	B,1
NOCONV:	AOS	C,OBP(CDB)	;MOVE A WORD OUT
	MOVEM	B,(C)
	ADDM	A,OCNT(CDB)
	MOVEI	B,11
	CAME	A,[-5]
	  IDPB	B,OBP(CDB)	;OUTPUT A TAB
NOTAB:	MOVE	LPSA,X33
	JRST	RESTR
LINBAD:	ERR <LINOUT:  Illegal JFN OR MODE>,
	JRST	NOTAB

	BEND LINOUT



DSCR 	STRSND,STRSN0
CAL	PUSHJ
SID	SAVES ALL ACS
ARGS
	1		JFN
	CDB		address of channel data block
	  
	1)  does the dump mode output only if there are characters
to be sent, accounting for only as much of the buffer as is full.
	2)  resets the OCNT and OBP variables.

	OCNT always has the number of free characters remaining
in the buffer.  This means that routines such as RELEASE can call
STRSND, and STRSND will be able to account for how many characters
need to be sent.  In this way, some of the classical problems
with counts are averted, since OCNT is honest.
	The exception, of course, is in the tight loops for
character transmission.  These are found in CHAROUT and OUT.
These are coded with (something like):

	SOSGE	OCNT(CDB)
	   PUSHJ P,STRSN0
	ILDB	CHAR,OBP(CDB)

At the call to STRSN0, OCNT is dishonest, reflecting the
fact that one character has already been promised.  Thus,
the same code cannot be used for STRSND and STRSN0.
Hence, two entries to the code here.

⊗

	BEGIN STRSND
↑↑STRSN0:
	AOS	OCNT(CDB)	;MAKE THE COUNT HONEST, TEMPORARILY
	PUSHJ	P,STRSND	;CALL STRSND
	SOS	OCNT(CDB)	;REFLECT THE FACT THAT A CHARACTER IS PROMISED
	POPJ	P,		;AND RETURN (TO CHARACTER OUTPUT CODE)

↑↑STRSND:
	PUSHJ	P,OPNCHK	;MAKE SURE OPEN
	PUSH	P,2		;SAVE ACS
	PUSH	P,3
	PUSH	P,4
	LDB	2,[POINT 4,OFL(CDB),9]	;GET MODE
	JUMPE	2,STRSOU	;USE SOUT
	CAIE	2,17		;BETTER BE DUMP MODE
	   ERR <STRSND:  MODE NOT 0 OR 17>
	HRRZI	3,STARTPAGE(1)	;GET THE PAGE NUMBER FOR THE BUFFER
	IMULI	3,1000		;MAKE AN ADDRESS

	SKIPN	OBP(CDB)	;INITIALIZED?
	  JRST	DMPINIT		;NO, JUST INITIALIZE
	MOVEI	4,DMOCNT*5
	CAMG	4,OCNT(CDB)	;ANY CHARS TO SEND
	  JRST	STRRET		;NO
	
	MOVEI	2,3
	SUBI	3,1
	MOVNI	4,DMOCNT	;WORD COUNT FOR DUMP MODE OUTPUT	
	HRL	3,4		;MAKE AN IOWD
	SETZ	4,		;MAKE A COMMAND LIST
	JSYS DUMPO
	  ERR <DUMPOUT:  CANNOT WRITE DATA IN DUMP MODE>,1
	SETOM	DMPED(CDB)	;AND INDICATE DONE
DMPINIT:
	MOVEI	3,STARTPAGE(1)
	IMULI	3,1000
	HRL	2,3
	HRRI	2,1(3)
	SETZM	(3)
	BLT	2,DMOCNT-1(3)	;ZERO OUT
	MOVEI	2,DMOCNT*5	
	MOVEM	2,OCNT(CDB)	;SAVE COUNT
	HLL	3,[POINT 7,0,-1];FIX A BYTE-POINTER
	MOVEM	3,OBP(CDB)	;AND SAVE BYTE-POINTER
STRRET:	POP	P,4		;RESTORE AND RETURN
	POP	P,3
	POP	P,2
	POPJ	P,

STRSOU:	SKIPN	OBP(CDB)	;INITIALIZED?
	   JRST	SOUINIT		;NO
	MOVEI	3,1000*5
	SUB	3,OCNT(CDB)	;NUMBER OF CHARACTERS ACTUALLY IN BUFFER
	IDIVI	3,5		;NUMBER OF WORDS
	SKIPE	4		;ANY REMAINDER?
	   AOJ	3,		;YES, ANOTHER WORD FOR EXTRA CHARACTERS
	JUMPE	3,STRRET	;RETURN IF NO CHARACTERS TO SEND
	MOVN	3,3		;NEGATIVE WORD COUNT FOR SOUT
	HRRZI	2,STARTPAGE(1)
	IMULI	2,1000		;CALCULATE ADDRESS
	HRLI	2,444400	;MAKE A BP
	JSYS SOUT
SOUINIT:
	HRRZI	2,STARTPAGE(1)
	IMULI	2,1000
	HRL	3,2
	HRRI	3,1(2)
	SETZM	(2)
	BLT	3,777(2)	;CLEAR OUT PAGE
	HRLI	2,440700
	MOVEM	2,OBP(CDB)
	MOVEI	3,1000*5
	MOVEM	3,OCNT(CDB)	
	JRST	STRRET

	BEND STRSND	

	
DSCR	SIMPLE PROCEDURE GTFDB(INTEGER JFN; REFERENCE INTEGER ARRAY BUF)

	Entire FDB of JFN is read into BUF.  No bounds checking,
so BUF should be at least '26 words.
⊗
HERE(GTFDB)
	PUSHJ	P,SAVE
	MOVE	LPSA,X33
	VALCHN	1,<-2(P)>,GTFBAD
	MOVSI	2,25		;ALL 25 WORDS
	HRRZ 	3,-1(P)		;ADDRESS OF ARRAY
	JSYS GTFDB
GTFRET:	JRST	RESTR

GTFBAD: ERR <Illegal JFN>,1
	JRST	GTFRET


ENDCOM(FIO)
COMPIL(BINROU,<WORDIN,WORDOUT,ARRYIN,ARRYOUT,MTOPR,SFPTR,RFPTR,BKJFN,RFBSZ>
	,<JFNTBL,X22,X33,.SKIP.,CDBTBL,SAVE,RESTR>
	,<BINROU -- BINARY ROUTINES>)
DSCR INTEGER SIMPLE PROCEDURE WORDIN(INTEGER JFN);
	Does the BIN jsys on JFN.
⊗
HERE(WORDIN)
	PUSH	P,2
	PUSH	P,CHNL
	PUSH	P,CDB
	VALCHN 1,<-4(P)>,BINBAD
	PUSHJ	P,OPNCHK
	SKIPE	ENDFL(CDB)
	  SETZM	@ENDFL(CDB)		;ASSUME NO EOF
	SETZM	.SKIP.			;ALSO MARK FOR EOF
	JSYS BIN
	JUMPE	2,CKWEOF		;CHECK EOF
	MOVE 1,2;
BINRET:	POP	P,CDB			;RESTORE 
	POP	P,CHNL
	POP	P,2
        SUB	P,X22
	JRST	@2(P)
BINBAD: ERR <Illegal JFN>,1
	SETZ	1,			;RETURN A NULL
	JRST	BINRET

CKWEOF:	JSYS GTSTS			;CHECK STATUS
	TESTE	2,<1B8>			;END-OF-FILE?
	     JRST [SKIPE ENDFL(CDB)	;EOF LOCATION
		      SETOM @ENDFL(CDB)	;YES
		   SETOM  .SKIP.	;ALSO MARK
		   JRST .+1]
	SETZ	1,			;RETURN NULL TO USER
	JRST	BINRET


DSCR SIMPLE PROCEDURE WORDOUT(INTEGER JFN,BYTE);
	Does the BOUT jsys.;
⊗
HERE(WORDOUT)
	PUSHJ	P,SAVE
	VALCHN	1,<-2(P)>,BOUBAD
	PUSHJ	P,OPNCHK
	MOVE	2,-1(P);
	JSYS BOUT
BOURET:	MOVE	LPSA,X33
	JRST	RESTR
BOUBAD: ERR <Illegal JFN>,1
	JRST	BOURET

DSCR SIMPLE PROCEDURE ARRYIN(INTEGER JFN; REFERENCE INTEGER LOC; INTEGER COUNT);
	Reads in COUNT words into LOC from JFN.  The file should be open
for 36-bit bytes for this to work.
	WARNING:  no array bounds checking.
⊗
HERE(ARRYIN)
	PUSHJ	P,SAVE
	MOVE	LPSA,X44
	MOVN	3,-1(P)		;NEGATIVE WORD COUNT
	JUMPE	3,ARIRET
	JUMPG	3,ARIBAD	;NEGATIVE WORD COUNT
	SKIPL	CHNL,-3(P)
	CAIL	CHNL,JFNSIZE
	   JRST	ARIBAD
	MOVE	CDB,CDBTBL(CHNL)	;GET CDB
	SKIPN	1,JFNTBL(CHNL)
	   JRST	ARIBAD
	SKIPE	ENDFL(CDB)	;EOF LOCATION?
	   SETZM @ENDFL(CDB)	;ASSUME GOOD
	SETZM  .SKIP.
	HRRZ	1,1		;THIS IS THE JFN NOW
	PUSHJ	P,OPNCHK	;MAKE CERTAIN WE ARE OPEN
	LDB	2,[POINT 4,OFL(CDB),9]	;GET THE MODE
	JUMPE	2,USESIN	;MODE ZERO?
	CAIE	2,17		;BETTER BE DUMP
	    JRST ARIBAD

USEDMP:	MOVEI	2,3
	HRL	3,3		;NEGATIVE WORD COUNT
	HRR	3,-2(P)		;ADDRESS OF BUFFER
	SUBI	3,1
	SETZB	4,.SKIP.	;ZERO NEXT LOCATION, ERROR WORD
	JSYS DUMPI
	   JRST	DMPERR
	JRST	ARIRET		;RETURN

USESIN:	MOVSI	2,444400	;BYTE-POINTER
	HRR	2,-2(P)		;LOCATION
	SETZM	.SKIP.		;ASSUME NO ERROR
	JSYS SIN
	SKIPE	3		;EVERYTHING READ ?
	   JRST	SINEOF
ARIRET:	JRST	RESTR

SINEOF:	ADD	3,-1(P)		;CALCULATE NO. OF WORDS READ IN
	HRLI	3,-1		;MAKE IT XWD -1,COUNT
	SKIPE	ENDFL(CDB)	;EOF LOCATION
	   MOVEM	3,@ENDFL(CDB)	;AND SAVE
	SETOM .SKIP.
	JRST	ARIRET


ARIBAD:	ERR <ARRYIN:  NEGATIVE WORD COUNT, Illegal JFN OR ILLEGAL MODE>,1
ARIBA1:	SETOM	.SKIP.
	JRST	ARIRET

DMPERR:	CAIN	1,600220	;END OF FILE?
	  JRST	DMPEOF
	ERR <ARRYIN:  DUMP MODE ERROR>,1
	JRST	ARIBA1

DMPEOF:	SKIPE	ENDFL(CDB)	;EOF LOCATION
	  SETOM	@ENDFL(CDB)	;INDICATE EOF
	SETOM .SKIP.
	MOVE	1,DVTYP(CDB)	;GET DEVICE TYPE
	CAIE	1,2		;IS IT MAGNETIC TAPE?
	  JRST	ARIRET		;NO
	HRRZ	1,JFNTBL(CHNL)	;THE JFN
	SETZ	2,
	JSYS MTOPR			;CLEAR STATUS
	JRST	ARIRET		;AND RETURN	


DSCR SIMPLE PROCEDURE ARRYOUT(INTEGER JFN; REFERENCE INTEGER LOC; INTEGER COUNT);
DESR 
	Writes COUNT words to JFN starting at LOC.  The file should be open
in 36-bit bytes.;
⊗

HERE(ARRYOUT)
	PUSHJ	P,SAVE
	MOVE	LPSA,X44
	MOVN	3,-1(P)		;COUNT
	JUMPE	3,ARORET	
	JUMPG	3,AROBAD	;NEGATIVE COUNT?
	SKIPL	1,-3(P)		;CHANNEL
	CAIL	1,JFNSIZE
	  JRST	AROBAD
	MOVE	CDB,CDBTBL(1)	
	SKIPN	1,JFNTBL(1)	
	  JRST	AROBAD
	HRRZ	1,1		;JFN
	PUSHJ	P,OPNCHK
	LDB	2,[POINT 4,OFL(CDB),9]	;GET THE MODE
	JUMPE	2,AROSOU 	;MODE ZERO?

	CAIE	2,17		;BETTER BE DUMP
	  JRST	AROBAD		;NOT OPEN IN DUMP MODE

ARODMP:	MOVEI	2,3
	HRL	3,3		;NEGATIVE WORD COUNT
	HRR	3,-2(P)
	SUBI	3,1		;MAKE AN IOWD
	SETZB	4,.SKIP.
	JSYS DUMPO
	   JRST	DMPOER
	SETOM	DMPED(CDB)	;INDICATE DUMP MODE
	JRST	ARORET		;RETURN

AROSOU:	MOVSI	2,444400	;BYTE-POINTER
	HRR	2,-2(P)		;LOCATION
	SETZM	.SKIP.
	JSYS SOUT
ARORET:	JRST	RESTR

AROBAD:	ERR <ARRYOUT:  NEGATIVE WORD COUNT, Illegal JFN OR ILLEGAL MODE>,1
AROBA1:	SETOM	.SKIP.
	JRST	ARORET

DMPOER:	ERR <ARRYOUT:  DUMP MODE ERROR>,1
	JRST	AROBA1


DSCR SIMPLE PROCEDURE MTOPR(INTEGER JFN,FUNCTION,VALUE)
	Does the MTOPR jsys.
⊗
HERE(MTOPR)
	BEGIN MTOPR
	PUSHJ	P,SAVE
	MOVE	LPSA,X44
	VALCHN 1,-3(P),MTBAD
	MOVE 	2,-2(P)
	MOVE	3,-1(P)
	JSYS MTOPR
MTRET:	JRST	RESTR

MTBAD:  ERR <Illegal JFN>,1
	JRST	MTRET

	BEND MTOPR

DSCR SIMPLE PROCEDURE SFPTR(INTEGER JFN,POINTER)
	Sets the file open on JFN to byte POINTER (-1 for EOF).
Errors returned in .SKIP.
	WARNING:  presently not compatible with special character
mode.
⊗
HERE(SFPTR)
	PUSHJ	P,SAVE
	MOVE	LPSA,X33
	VALCHN 1,-2(P),SFBAD
	SETZM	.SKIP.
	MOVE 2,-1(P)
	JSYS SFPTR
	  MOVEM	1,.SKIP.
SFRET:	JRST	RESTR

SFBAD:  ERR <Illegal JFN>,1
	SETOM	.SKIP.
	JRST	SFRET




DSCR INTEGER SIMPLE PROCEDURE RFPTR(INTEGER JFN)
	Reads the pointer of JFN.  Error codes to .SKIP.
	WARNING:  presently does not work for files in special character
mode.
⊗
HERE(RFPTR)
	PUSHJ	P,SAVE
	MOVE	LPSA,X22
	VALCHN	1,-1(P),RFBAD
	SETZM	.SKIP.
	JSYS RFPTR
	MOVEM 1,.SKIP.
	MOVEM	2,RACS+A(USER)	;ANSWER IN 2
RFRET:	JRST	RESTR

RFBAD:  ERR <Illegal JFN>,1
	SETOM	.SKIP.
	JRST	RFRET

DSCR SIMPLE PROCEDURE BKJFN(INTEGER JFN)
	Does the BKJFN jsys on JFN, error code to .SKIP.
⊗
HERE(BKJFN)
	PUSHJ	P,SAVE
	MOVE	LPSA,X22
	VALCHN 1,-1(P),BKBAD
	SETZM	.SKIP.
BKJF1:	JSYS BKJFN
	MOVEM 1,.SKIP.			;ERROR RETURN
BKRET:	JRST	RESTR

BKBAD:  MOVE	1,-1(P)			;USE LITERALLY
	JRST	BKJF1
DSCR INTEGER SIMPLE PROCEDURE RFBSZ(INTEGER JFN);
	Reads the byte-size of the file open on JFN.
⊗
HERE(RFBSZ)
	PUSHJ	P,SAVE
	MOVE	LPSA,X22
	VALCHN 1,-1(P),RFBBAD
	JSYS RFBSZ
	MOVEM	2,RACS+A(USER)		;ANSWER IN 2
RFBRET:	JRST	RESTR

RFBBAD: ERR <Illegal JFN>,1
	JRST	RFBRET
ENDCOM(BINROU)

IMSSS,<
COMPIL(DSKOPS,<DSKIN,DSKOUT>
	,<JFNTBL,CDBTBL,.SKIP.>
	,<DSKOPS -- DIRECT DSK ROUTINES>)

DSCR SIMPLE PROCEDURE 
DSKIN(INTEGER MODULE,RECNO,COUNT; REFERENCE INTEGER LOC);

	IMSSS only.
	Does direct IO from the DSK (formerly device "PAK").
Modules 4-7 are legal for everyone.  Other modules require enabled
status.
	Count words are read into user's core at location LOC, from
MODULE, record RECNO.  Error bits are in .SKIP.
	Does the DSKOP jsys (as modified at IMSSS).
⊗

	BEGIN DSKOPS
HERE(DSKIN)
	PUSHJ	P,SAVE
	SETZ	4,		;INDICATE READ ONLY

DSK1:	HRRZ	2,-2(P)
	JUMPLE	2,DSBAD	;LEQ 0 -- ERROR
	CAILE	2,1000		;DONT READ MORE THAN 1000 WORDS
	   JRST DSBAD
	IOR	2,4		;PICK UP READ OR WRITE (SET IN 4)
	HRLZ	1,-4(P)		;MODULE
	HRR	1,-3(P)		;RECORD NO. IN RIGHT HALF
	TLO	1,600000	;SOFTWARD ADDRESS, IMSSS FORMAT (BITS 0 AND 1 RES.)
	HRRZ 	3,-1(P) 		; GET THE USER LOCATION
    	JSYS DSKOP
DSDUN:	MOVEM 1,.SKIP.		; SAVE ERROR BITS
DSRET:	MOVE 	LPSA,[XWD 5,5]	; TO ADJUST STACK
	JRST	RESTR
DSBAD:	ERR <DSKIN OR DSKOUT:  WORD COUNT EITHER <= 0 OR > '1000>,1
	SETOM	.SKIP.
	JRST	DSRET



DSCR SIMPLE PROCEDURE 
	DSKOUT(INTEGER MODULE,RECNO,COUNT; REFERENCE INTEGER LOC)
DESR Similar to DSKIN, except that a write is done.
⊗

HERE(DSKOUT)
	PUSHJ	P,SAVE
	MOVSI	4,(1B14)	;INDICATE WRITE (TO BE IOR'ED INTO AC 2)
	JRST	DSK1		;AND TO THE ABOVE CODE

	BEND DSKOPS

ENDCOM(DSKOP)
>;IMSSS

COMPIL(DEVS,<DEVTYPE,DVCHR,ERSTR>
	,<X22,X44,.SKIP.,JFNTBL,CDBTBL>
	,<DEVS -- DEVICE HANDLERS, ERROR ROUTINE>)
DSCR INTEGER SIMPLE PROCEDURE DEVTYPE(INTEGER JFN);
	Returns (via the DEVCHR jsys) the device type of
the device open on JFN.  The more general DEVCHR call is
also implemented (below).
⊗
HERE(DEVTYPE)
	VALCHN 1,-1(P),DEVBAD
	JSYS DVCHR
	HLRZ	1,2
	ANDI	1,777
DEVRET:	SUB	P,X22
	JRST	@2(P)
DEVBAD: ERR <Illegal JFN>,1
	JRST	DEVRET
DSCR INTEGER SIMPLE PROCEDURE DVCHR(INTEGER JFN; REFERENCE INTEGER AC1,AC3);
	Does the DEVCHR jsys, returning the flags from AC2 as the
value of the call, and AC1 and AC3 get the contents of ac's 1 and 3.;
⊗
HERE(DVCHR)
	VALCHN 1,-3(P),DVBAD
	JSYS DVCHR
	MOVEM	1,@-2(P)
	MOVEM	3,@-1(P)
	MOVE	1,2
DVRET:	SUB	P,X44
	JRST	@4(P)
DVBAD: ERR <Illegal JFN>,1
	JRST	DVRET
	

DSCR SIMPLE PROCEDURE ERSTR(INTEGER ERRNO,FORK)
	Using the ERSTR jsys, types out on the console the TENEX error string
associated with ERRNO for FORK fork (0 for the current fork).  Parameters (in
the sense of the ERSTR jsys) are expanded.
	Types out the string ERSTR:  UNDEFINED ERROR number if
something is with your error number or fork (and sets .SKIP. to -1).
⊗
HERE(ERSTR)
	SETZM	.SKIP.
	MOVEI	1,101		;PRIMARY OUTPUT
	SKIPN	2,-1(P)		;ANY FORK MENTIONED?
	   MOVEI 2,400000	;ASSUME CURRENT FORK
	HRLZ	2,2		;IN LEFT HALF
	HRR	2,-2(P)		;THE ERROR NUMBER
	SETZ	3,		;NO LIMIT TO SIZE OF STRING
	JSYS ERSTR
	   JRST	ERSERR		
	   JRST	ERSERR		;ERROR RETURNS
ERSRET:	SUB	P,X33
	JRST	@3(P)
ERSERR:	HRROI	1,[ASCIZ/
ERSTR:  UNDEFINED ERROR NUMBER
/]
	JSYS PSOUT
	SETOM	.SKIP.		;INDICATE ERROR 
	JRST	ERSRET
ENDCOM(DEVS)

COMPIL(UTILITY,<SETCHN,ZSETST,ZADJST,.RESET>
	,<CORGET,GOGTAB,JFNTBL,CDBTBL,STRNGC,INSET>
	,<UTILITY -- UTILITY TENEX ROUTINES>)
DSCR
	SETCHN accepts in A the JFN, and returns in A the channel number associated with a JFN.  
It sets up the JFNTBL, the CDBTBL table, and returns the address of the
file command block in ac CDB.  Other acs are not modified (except USER).
	In order to accommodate the open statement, a channel will be
considered allocated when it has a CDB, even if it does not yet have a jfn.
⊗

HERE(SETCHN)
	MOVE	USER,GOGTAB
	PUSH	P,B
	PUSH	P,C
	PUSH	P,D

	SKIPE	CDBTBL(A)		;CAN WE USE THE SAME CHANNEL AS JFN?
	   JRST FNDCHN			;PERHAPS NOT, FIND ONE SOME HOW
	HRRZ	D,A			;USE JFN AS CHANNEL
;MUST GET A CHANNEL DATA BLOCK
GTCDB:	MOVEI	C,IOTLEN
	PUSHJ	P,CORGET
	   ERR <SETCHN:  NO CORE>
	MOVE	CDB,B
	MOVEM	CDB,CDBTBL(D)		;SAVE ADDR OF CDB
;HERE WITH B,CDB, D LOADED WITH: CDBADDR,CDBADDR,CHANNEL
CLCDB:	
	HRL	B,B
	ADDI	B,1
	SETZM	(CDB)
	BLT	B,IOTLEN-1(CDB)

GOTCHN:	
	MOVEM 	A,JFNTBL(D)
	HRRZ	1,A			;JFN
	JSYS DVCHR				;CLOBBERS 1,2,3
	MOVEM	1,DVDSG(CDB)		;SAVE DESIGNATOR
	MOVEM	2,DVCH(CDB)		;AND CHARACTERISTICS
	HLRZ	1,2
	ANDI	1,777			;GET DEVICE TYPE
	MOVEM	1,DVTYP(CDB)		;AND SAVE IT
	HRRZ	A,D			;CHANNEL INTO A
	POP	P,D			;RESTORE
	POP	P,C			
	POP	P,B
	POPJ	P,


;FIND AN OPEN CHANNEL AND RETURN THE NUMBER IN D
;A HAS THE JFN NO. IN IT, SO CHECK TO SEE IF THE SAME
;B MAY BE CLOBBERED
FNDCHN:	HRRZ	D,JFNTBL(A)		;CHECK OLD JFN
	CAIE	D,(A)			;SAME AS THE NEW?
	  JRST  FNDCH2			;NO
	MOVE	CDB,CDBTBL(D)		;GET OLD CDB
	MOVE	B,CDB			;COPY CDB ADDR FOR BLT
	JRST	CLCDB			

FNDCH2:	SETZ	D,
FNDCH1:	CAIL	D,JFNSIZE
	   ERR <SETCHN:  JFN TABLE IS FULL (SHOULD NEVER HAPPEN)>
	SKIPE	CDBTBL(D)		;IS IT EMPTY?
	  AOJA	D,FNDCH1	   	;NO LOOK SOME MORE
	JRST	GTCDB			;YES, USE IT


DSCR SIMPLE INTEGER PROCEDURE ZSETST(INTEGER I);

	Internal book-keeping routine not intended for
use from SAIL.  Causes liberation from SAIL.

	THE ARGUMENT IS THE MAXIMUM SIZE OF THE EXPECTED STRING.
THE RETURN IS THE BYTEPOINTER POINTING INTO THE TOP OF STRING SPACE
⊗

HERE(ZSETST)
	MOVE USER,GOGTAB 		; GET USER
	SKIPE	SGLIGN(USER)
	  PUSHJ	P,INSET			;ASSUMING THAT IT IS TRANSPARENT FOR THE ACS
	MOVE	1,-1(P)		;GET EXPECTED LENGTH
	ADDM 1,REMCHR(USER) 		; ADD ON
	SKIPLE REMCHR(USER) 		; NEED TO COLLECT?
	  PUSHJ P,GOCOLLECT 		; YES
	MOVE 1,TOPBYTE(USER) 		; RETURN BP
	SUB P,X22 			; ADJUST STACK
	JRST @2(P) 			; RETURN

GOCOLLECT:	
	MOVEM	RF,RACS+RF(USER)	;SAVE RF
	PUSHJ P,STRNGC ;
	POPJ P, 			; RETURN TO ABOVE

DSCR STRING SIMPLE PROCEDURE ZADJST(INTEGER CNTEST,BP)
	Internal book-keeping routine.
	ADJUSTS THE PARAMETERS ASSOCIATED WITH STRING SPACE.
BP IS OUR NEW TOPBYTE.  CNTEST IS THE COUNT ESTIMATE WE
ORIGINALLY MADE.
	FIRST, WE MUST MAKE REMCHR HONEST, THEN WE
	CAN FIX TOPSTR AND THE USER'S LENGTH WORD.
⊗
HERE(ZADJST)
	BEGIN ZADJST


	MOVE USER,GOGTAB;	
	PUSH	P,1
	PUSH	P,2
	PUSH	P,3
	PUSH	P,4

DEFINE CNTARG <-6(P)>
DEFINE BPARG <-5(P)>

	MOVE	2,BPARG			;UPDATED BP
	MOVE 	1,TOPBYTE(USER) 	; GET OLD TOPBYTE
	CAMN 	1,2 			; THE NULL STRING?
	  JRST NULRET;			;YES
;P. KANERVA'S BYTE ROUTINE
	LDB	3,[POINT 6,1,5]		;BITS TO THE RIGHT OF BYTE 1
	LDB	4,[POINT 6,2,5]		;BITS TO THE RIGHT OF BYTE 2
	SUBI	3,(4)			;BIT DIFFERENCE
	IDIVI	3,7			;WITHIN-WORD BYTE DIFFERENCE
	
	SUBI	2,(1)			;WORDS BETWEEN BYTES
	HRRE	2,2			;FULL WORD DIFFERENCE
	IMULI	2,5			;CONVERT IT TO BYTE DIFFERENCE
	ADD	2,3			;ADD COUNT DERIVED FROM WITHIN-WORD
					;DIFFERENCE

	CAMLE	2,CNTARG		;WITHIN RANGE?
	  ERR <ZADJST:  TENEX WROTE TOO LONG A STRING, MAY BE FATAL>,1
GOTLNG:	HRRO	1,2			; XWD -1,COUNT
	PUSH 	SP,1 			; XWD -1,COUNT
       	PUSH 	SP,TOPBYTE(USER) 	; OLD TOPBYTE FOR BP FOR STRING
	SUB 	2,CNTARG		; SUBTRACT THE COUNT ESTIMATE
	ADDM 	2,REMCHR(USER) 		; MAKE REMCHR HONEST
	MOVE	2,BPARG			; GET THE NEW TOPBYTE
	MOVEM 	2,TOPBYTE(USER) 	; AND SAVE IT
	POP	P,4
	POP	P,3			
	POP	P,2
	POP	P,1
	SUB 	P,X33 			; ADJUST STACK
	JRST @3(P) ;

NULRET:	SETZ 2,;
	JRST GOTLNG 			; BE SURE TO FIX UP ALL THE GOODIES
	
	BEND ZADJST

DSCR
	.RESET
SID	SAVES ALL ACS
CAL	PUSHJ, FROM SAIL AND THE COMPILER

	RESETS TENEX IO AND BOOKKEEPING, AND SETS THE TTY MODE TO WAKEUP
ON EVERY CHARACTER.
THIS SHOULD ONLY BE CALLED INTERNALLY
⊗
HERE(.RESET)
BEGIN RESET
;ZERO OUT BOOKKEEPING
	PUSH	P,1
	PUSH	P,2
	PUSH	P,3
	SETZM	JFNTBL
	MOVE	1,[XWD JFNTBL,JFNTBL+1]
	BLT	1,JFNTBL+JFNSIZE-1
	SETZM	CDBTBL
	MOVE	1,[XWD CDBTBL,CDBTBL+1]
	BLT	1,CDBTBL+JFNSIZE-1

;RELEASE PAGES ASSOCIATED WITH FILES (FROM STARTPAGE TO STARTPAGE+JFNSIZE-1)
	SETO	1,			;RELEASE PAGE
	SETZ	3,			;FLAGS WORD
	MOVE	2,[XWD 400000,STARTPAGE]
.RESE1:	CAMN	2,[XWD 400000,STARTPAGE+JFNSIZE]	;THIS WOULD BE TOO MANY PAGES
	  JRST .RESE2
	JSYS	PMAP			
	AOJA	2,.RESE1		;NEXT?

.RESE2:
	JSYS RESET		;CLEAR ALL IO

;SET UP PSI SYSTEM
	HRRZI	1,400000	;USE EXISTING TABLE IF THERE
	JSYS	RIR
	JUMPN	2,.+3		;ALREADY THERE
	MOVE	2,[XWD LEVTAB,CHNTAB]
	JSYS	SIR
	JSYS	EIR		;TURN ON INTERRUPTS

;SET PRIMARY INPUT TO WAKE UP ON EVERY CHARACTER
;THE USER MAY RESET THIS.
	MOVEI	1,100		;PRIMARY INPUT
	JSYS RFMOD
	TRO	2,170000	;WAKEUP ON ALL CHARS
	JSYS SFMOD
	SETZM	CTLOSW		;CLEAR OUTPUT-SUPPRESSION SWITCH

	POP	P,3
	POP	P,2
	POP	P,1
	POPJ	P,
BEND RESET

;ROUTINE TO CHECK IF A JFN HAS BEEN CLOSED BY ONE OF
;THE DEC-STYLE CLOSE ROUTINES (IN WHICH CASE IT
;MUST BE AVAILABLE FOR RE-OPENING)
;ARGS:
;	1	JFN
;	CDB	THE CHANNEL DATA BLOCK
;	CHNL	THE CHANNEL NUMBER
↑OPNCHK:
	SKIPN	DECCLZ(CDB)		;CLOSED BY DEC?
	   POPJ P,			;NO
	PUSH	P,2			;SAVE 2
	MOVE	2,OFL(CDB)		;PREVIOUSLY USED FLAGS
	JSYS	OPENF			;OPEN
	   ERR <OPNCHK:  CANNOT OPENF FILE>
	SETZM	DECCLZ(CDB)
	POP	P,2			;RESTORE 2
	POPJ	P,			;RETURN

;SIMILAR TO OPNCHK EXCEPT THAT 
;ARGS:
;	CHNL	THE CHANNEL NUMBER
;	CDB	THE CHANNEL DATA BLOCK
↑OPNCH1:
	SKIPN	DECCLZ(CDB)		;CLOSED BY DEC?
	   POPJ	P,
	PUSH	P,1
	PUSH	P,2
	HRRZ	1,JFNTBL(CHNL)
	MOVE	2,OFL(CDB)
	JSYS	OPENF
	   ERR <OPNCHK:  CANNOT OPENF FILE>
	POP	P,2
	POP	P,1
	POPJ	P,			;RETURN;
ENDCOM(UTILITY)
COMPIL(TTM,<RFMOD,SFMOD,RFCOC,SFCOC>
	,<SAVE,RESTR,X22,X33,X44>
	,<TTM -- TERMINAL MODE ROUTINES>)

DSCR INTEGER PROCEDURE RFMOD(INTEGER CHAN)

	Reads a file's mode word.

     PROCEDURE SFMOD(INTEGER CHAN,AC2)

	Sets a file's mode word to argument AC2.

     PROCEDURE RFCOC(INTEGER CHAN; REFERENCE INTEGER AC2,AC3)

	Does RFCOC jsys, returning values in AC2 and AC3.

     PROCEDURE SFCOC(INTEGER CHAN,AC2,AC3)

	Does SFCOC jsys, setting to AC2 and AC3.


⊗

HERE(RFMOD)
	PUSHJ	P,SAVE
	MOVE	LPSA,X22
	VALCH1	1,-1(P),RFMO1
RFMO2:	JSYS	RFMOD
	MOVEM	2,RACS+A(USER)
	JRST	RESTR
RFMO1:	MOVE	1,-1(P)		;USE LITERALLY
	JRST	RFMO2



HERE(SFMOD)
	PUSHJ	P,SAVE
	MOVE	LPSA,X33
	VALCH1	1,-2(P),SFMO1
SFMO2:	MOVE	2,-1(P)
	JSYS SFMOD
	JRST	RESTR
SFMO1:	MOVE	1,-2(P)
	JRST	SFMO2

HERE(RFCOC)
	PUSHJ	P,SAVE
	MOVE	LPSA,X44
	VALCH1	1,-3(P),RFCO1
RFCO2:	JSYS	RFCOC
	MOVEM	2,@-2(P)
	MOVEM	3,@-1(P)
	JRST	RESTR
RFCO1:	MOVE	1,-3(P)		;USE LITERALLY
	JRST 	RFCO2

HERE(SFCOC)
	PUSHJ	P,SAVE
	MOVE	LPSA,X44
	VALCH1	1,-3(P),SFCO1
SFCO2:	MOVE	2,-2(P)
	MOVE	3,-1(P)	
	JSYS	SFCOC
	JRST	RESTR
SFCO1:	MOVE	1,-3(P)		;USE LITERALLY
	JRST	SFCO2


ENDCOM(TTM)

COMPIL(PAGES,<PMAP>,<SAVE,RESTR,X44>
	,<PAGES -- PAGE MANAGEMENT>)
DSCR SIMPLE PROCEDURE PMAP(INTEGER AC1,AC2,AC3);
DESR
	Does the PMAP jsys, with these parameters:

ARGUMENTS:	
	AC1		contents of AC1
	AC2		  "	 of AC2
	AC3		  "	 of AC3

⊗
HERE(PMAP)
	PUSHJ	P,SAVE
	MOVE	LPSA,X44
	MOVE	1,-3(P)			;FILEPAGE
	MOVE	2,-2(P)			;XWD FORK,PAGE
	MOVE 	3,-1(P)			;ACCESS BITS
	JSYS PMAP
	JRST	RESTR
ENDCOM(PAGES)
IMSSS,<
COMPIL(TT2,<PBTIN,INTTY>
	,<X22,.SKIP.,ZSETST,ZADJST,CTLOSW>
	,<TT2 -- IMSSS TTY ROUTINES>)

DSCR INTEGER SIMPLE PROCEDURE PBTIN(INTEGER SECONDS);
DESR 
	Executes the PBTIN jsys, with timing of SECONDS.
⊗
HERE(PBTIN)
	SETZM	CTLOSW			;PROGRAM REQUESTS INPUT
	MOVE	1,-1(P)			;TIME IN SECONDS
	JSYS PBTIN
	SUB	P,X22
	JRST	@2(P)

DSCR STRING SIMPLE PROCEDURE INTTY;
	Using the PSTIN jsys, accepts as many as 200 characters from
the user's Teletype, with the standard system breakcharacters.  The
breakcharacter itself is removed from the string, and
no timing is available.  For fancier calls, see PSTIN routine.
⊗

HERE(INTTY)
	PUSH	P,1
	PUSH	P,2
	PUSH	P,3
	SETZB	3,CTLOSW		;PROGRAM REQUESTS INPUT
	MOVEI	2,=200			;DEFAULT LENGTH
INTT2:	PUSH	P,2			;LENGTH
	PUSHJ	P,ZSETST		;GET BP IN 1
	JSYS PSTIN
	CAIL	2,=200			;DID WE GET 200 CHARS?
	   JRST	[SETOM	.SKIP.
		 JRST	INTT1]
	LDB	3,1			;GET THE LAST CHAR
	MOVEM	3,.SKIP.		;AND SAVE IT
	SOJ	1,			;BACK UP BYTE-POINTER (OVER LAST CHAR)
	IBP	1
	IBP	1
	IBP	1
	IBP	1
INTT1:	PUSH	P,[=200]
	PUSH	P,1
	PUSHJ	P,ZADJST		;GET STRING ON STACK
	POP	P,3	
	POP	P,2
	POP	P,1
	POPJ	P,			;RETURN


ENDCOM(TT2)
>;IMSSS

NOIMSSS<;NON-IMSSS VERSION OF INTTY FOR THOSE WHO SUFFER
;UNDER BBN'S LACK OF A SYSTEM LINE EDITOR

COMPIL(TT2,<INTTY>
	,<X11,.SKIP.,ZSETST,ZADJST,CTLOSW,SAVE,RESTR>
	,<TT2 -- INTTY FOR TENEX STYLE INPUT>)
DSCR INTTY


⊗;
HERE(INTTY)
	BEGIN INTTY
ORIGCNT←←=200
;AC USES  A,B,C  JSYS TEMPORARIES
;	  D	 BYTEPOINTER
;	  E	 COUNT, INITIALLY 0
;	  Q1 (=6) ORIGINAL BP


	PUSHJ	P,SAVE
	SETZM	CTLOSW
	MOVEI	A,101
	JSYS	RFMOD
	PUSH	P,B			;SAVE THE TTY MODE
	TRO	B,170000		;WAKEUP ON EVERYTHING
	JSYS	SFMOD
	
	PUSH	P,[ORIGCNT]		;
	PUSHJ	P,ZSETST		;GET A GOOD BP IN A
	MOVE	Q1,A



RESTRT:	MOVE	D,Q1			;GET THE ORIGINAL BP	
	SETZ	E,			;ZERO THE COUNT
INLUP:	CAIL	E,ORIGCNT
	  JRST	CNTEXH			;COUNT EXHAUSTED
	JSYS	PBIN			;GET A CHAR
	CAIE	A,37			;EOL?
	CAIN	A,33			;ESCAPE?
	  JRST	DONE
	CAIE	A,32			;CTRL-Z
 	CAIN	A,7			;CTRL-G
	  JRST	DONE
	CAIE	A,"R"-100		;CTRL-R FOR REPEAT
	  JRST	NOCTR	
	HRROI	A,[ASCIZ/
/]
	JSYS	PSOUT
	JUMPE	E,INLUP
	MOVEI	A,101
	MOVE	B,Q1			;ORIG BP
	MOVN	C,E			;COUNT THUS FAR
	JSYS	SOUT
	JRST	INLUP			;AND CONTINUE
NOCTR:	CAIE	A,"X"-100		;CONTROL-X FOR DELETE LINE
	  JRST	NOCTX
DOCTX:	HRROI	A,[ASCIZ/
/]
	JSYS	PSOUT
	JRST	RESTRT			;AND START ALL OVER
NOCTX:	CAIE	A,177			;RUBOUT OR
	CAIN	A,"A"-100		;CONTROL-A
	  JRST	.+2
	 JRST	NOCTA
	JUMPLE	E,DOCTX			;IF NO CHARS THEN DO A CONTROL-X
	MOVEI	A,"\"
	JSYS	PBOUT
	LDB	A,D			;LAST CHAR
	JSYS	PBOUT	
	MOVE	A,D
	JSYS	BKJFN
	  JFCL
	MOVEM	A,D			;BACK UP BP
	SOJA	E,INLUP			;SUBTRACT 1 AND CONTINUE
NOCTA:	IDPB	A,D
	AOJA	E,INLUP			;ONE MORE CHAR	

CNTEXH:	SETO	A,			;INDICATE NO COUNT
DONE:	MOVEM	A,.SKIP.		;BREAK CHAR, -1 FOR EXHAUSTED
	PUSH	P,[ORIGCNT]	
	PUSH	P,D			;NEW BP
	PUSHJ	P,ZADJST		;FIX UP STRING SPACE, PUT STRING ON STACK
	MOVEI	A,101
	POP	P,B			;MODE SETTING
	JSYS	SFMOD			;RESET
	MOVE	LPSA,X11
	JRST	RESTR			;AND RETURN

	BEND INTTY
ENDCOM(TT2)
>;NOIMSSS
COMMENT ⊗ TTY FUNCTIONS ⊗


DSCR TTY FUNCTIONS
CAL SAIL
⊗

Comment ⊗
INTEGER PROCEDURE INCHRW;
 RETURN A CHAR FROM PBIN

INTEGER PROCEDURE INCHRS;
 RETURN -1 IF NO CHAR WAITING, ELSE FIRST CHAR (SIBE FOLLOWED BY PBIN)

STRING PROCEDURE INCHWL;
 WAIT FOR A LINE, THEN RETURN IT (PBINs, LINE EDITING)

STRING PROCEDURE INCHSL(REFERENCE INTEGER FLAG);
 FLAG←-1, STR←NULL IF NO LINE, ELSE FLAG←0, 
	STR←LINE (SIBE, FOLLOWED BY PBINs)

STRING PROCEDURE INSTR(INTEGER BRCHAR);
 RETURN ALL CHARS TO AND NOT INCLUDING BRCHAR (PBINs)

STRING PROCEDURE INSTRL(INTEGER BRCHAR);
 WAIT FOR ONE LINE, THEN DO INSTR (PBINs WITH EDITING)

STRING PROCEDURE INSTRS(REFERENCE INTEGER FLAG; INTEGER BRCHAR);
 FLAG←-1, STR←NULL IF NO LINES, ELSE FLAG←0, 
  STR←INSTR(BRCHAR)


PROCEDURE OUTCHR(INTEGER CHAR);
 OUTPUT CHAR (PBOUT)

PROCEDURE OUTSTR(STRING STR);
 OUTPUT STR (SOUT)


PROCEDURE CLRBUF;
 CLEARS INPUT BUFFER (CFIBF)

TTYIN, TTYINS, TTYINL (TABLE, @BRCHAR);
 TTYIN WORKS WITH TTCALL 0'S; TTYINS DOES A SKIP
 ON LINE FIRST, RETURNING NULL AND -1 IN BREAK IF NO LINES
 TTYINL DOES A WAIT FOR LINE FIRST.
 FULL BREAKSET CAPABILITIES EXCEPT FOR 
 "R" MODE (AND OF COURSE, LINE NUM. STUFF)

	TITLE	TTYUUO
⊗

COMPIL(TTY,<PBIN,PBOUT,PSOUT,INCHRW,INCHRS,INCHWL,INCHSL,INSTR,OUTCHR,OUTSTR,INSTRL,INSTRS,CLRBUF,TTYIN,TTYINS,TTYINL,TTYUP
>
	  ,<SAVE,RESTR,X11,X22,X33,INSET,CAT,STRNGC,GOGTAB,BRKMSK,.SKIP.,CTLOSW>
	  ,<TELETYPE FUNCTIONS>)
;;#GF# DCS 2-1-72 (1-3) INCHWL BREAKS ON ALL ACTIVATION, TELLS WHICH IN .SKIP.
; .SKIP. EXTERNAL ABOVE
;;#GF#
 
HERE(PBIN)
HERE (INCHRW)
	SETZM	CTLOSW		;INPUT REQUESTED
INCHR1:	JSYS PBIN
	POPJ	P,

HERE (INCHRS)
	SETZM	CTLOSW		;INPUT REQUESTED
	MOVEI	1,100
	JSYS SIBE
	   JRST	INCHR1
	SETO	1,		;RETURN -1
	POPJ	P,

HERE(PBOUT)
HERE (OUTCHR)	
	SKIPE	CTLOSW		;DOING OUTPUT?
	  JRST	OUTCRE		;NO
	EXCH	1,-1(P)		;GET PARAMETER, SAVING AC 1
	JSYS PBOUT			;OUTPUT CHAR	
	EXCH	1,-1(P)		;GET BACK 1	
OUTCRE:	SUB	P,X22
	JRST	@2(P)		;RETURN


HERE(PSOUT)
HERE (OUTSTR)
	SKIPE	CTLOSW		;DOING OUTPUT?
	  JRST	[SUB SP,X22
		 POPJ P,
		]
	EXCH	2,(SP)		;BP WORD
	EXCH	3,-1(SP)	;LENGTH WORD
	PUSH	P,1		;ALSO NEED 1
	HRRZ	3,3		;COUNT
	JUMPE	3,NULSTR	;DONT SEND EMPTY STR
	MOVEI	1,101		;TERMINAL OUTPUT
	MOVN	3,3
	JSYS SOUT
NULSTR:	POP	P,1
	POP	SP,2
	POP	SP,3		;ADJUSTS STACK AUTOMATICALLY
	POPJ 	P,		;RETURN

;REDSTR (0) MARKS CTLOSW THAT INPUT WAS REQUESTED
;(1) PREPARES TO MAKE A STRING OF 200 CHARS, 
;(2) ZEROS C FOR COUNT
;(3) SETS UP D WITH THE ORIGINAL BYTE-POINTER

REDSTR:	SETZM	CTLOSW		;INPUT REQUESTED
	SKIPE	SGLIGN(USER)
	PUSHJ	P,INSET
	MOVEI	A,=200
	ADDM	A,REMCHR(USER)
	SKIPLE	REMCHR(USER)
	PUSHJ	P,STRNGC
	SETZ	C,		;COUNT HERE
	MOVE	D,TOPBYTE(USER)	;ORIGINAL BYTE-POINTER, IF NEEDED
	PUSH	SP,[0]		;NULL STRING IF NOTHING DONE
	PUSH	SP,TOPBYTE(USER)
	POPJ	P,

FINSTR:	MOVEI	A,=200
	SUB	A,C		;NUMBER USED
	ADDM	A,REMCHR(USER)
	HRROM	C,-1(SP)	;STRING COUNT WORD
	MOVEM	D,TOPBYTE(USER)	;NEW TOPBYTE
	JRST	RESTR

;CALL TO HERE WITH A PUSHJ TO GET A CHAR IN AC1
;AC 3 HAS THE COUNT, D THE BYTE-POINTER
EDICHR:
	JSYS PBIN			;GET A CHARACTER
	CAIN	1,DELLINE	;DELETE LINE CHAR
	   JRST	CTRLU
	CAIN	1,RUBCHAR	;RUBOUT?
	   JRST	RUBOUT
	CAIN	1,37		;PHONEY TENEX EOL?
	   MOVEI 1,12
	CAIN	1,33		;PHONEY TENEX ALTMODE?
	  MOVEI 1,ALTMODE	;DEC ALTMODE
	POPJ	P,		;GOOD CHAR FOR USER
	
CTRLU:	
;AC 1 IS FREE
	HRROI	1,[BYTE (7) 7,15,12,0,0]
	JSYS PSOUT	
	JUMPE	C,EDICHR	;IF NO CHARS THEN DO NOTHING
	SETZ	C,
	MOVE	D,TOPBYTE(USER)
	JRST	EDICHR

RUBOUT:	JUMPE	C,CTRLU		;IF NO CHARS THEN DO CTRLU
;AC 1 IS AVAILABLE
IMSSS<
	MOVEI	1,101		;PRIMARY OUTPUT
	JSYS	DELCH
	  JFCL
	  JRST	DLTED		;DISPLAY -- LINE EMPTY
	  JRST	DLTED		;DISPLAY -- DELETE DONE
>;IMSSS
	MOVEI	1,"\"
	JSYS PBOUT
	LDB	1,D		;GET LAST CHAR
	JSYS PBOUT			;AND SEND IT
DLTED:
	SOJ	D,		;BACK UP BP TO LAST CHAR
	IBP	D
	IBP	D
	IBP	D
	IBP	D
	SOJA	C,EDICHR	;AND GET ANOTHER CHAR

HERE(INSTRL)
HERE (INSTR) 
	PUSHJ	P,SAVE
	PUSHJ	P,REDSTR
	MOVE	B,-1(P)		;BREAK CHAR
	MOVE	LPSA,X22	;# TO REMOVE

INS1:	CAIL	C,=200		;COUNT EXHAUSTED?
	 JRST	FINSTR		;YES
INS2:	PUSHJ	P,EDICHR	;GET A CHAR IN 1, USING EDITING
	CAMN	1,B		;BREAK?
	 JRST	 FINSTR		; YES, ALL DONE
	IDPB	1,D		;PUT IT AWAY AND
	AOJA	C,INS1

HERE (INCHWL)	PUSHJ	P,SAVE
	PUSHJ	P,REDSTR
	MOVE	LPSA,X11

INS3:	CAIL	C,=200		;COUNT EXHAUSTED?
	  JRST	DNSTR1		;YES
	PUSHJ	P,EDICHR	;GET A CHAR
	CAIE	1,ALTMODE
	CAIN	1,12
	   JRST	DNSTR
	CAIN	1,15		;CR?	
	   JRST	INS3		;IGNORE
	IDPB	1,D		;PUT IT AWAY AND
	AOJA	C,INS3		;NEXT CHARACTER

DNSTR:	MOVEM	1,.SKIP.	;SET BREAK CHAR
	JRST	FINSTR
DNSTR1:	SETOM	.SKIP.		;INDICATE COUNT EXHAUSTED
	JRST	FINSTR


HERE (INCHSL)	PUSHJ	P,SAVE
	MOVE	LPSA,X22	;PARAM (FLAG) AND RETURN
	PUSHJ	P,REDSTR
	SETOM	@-1(P)		;ASSUME FAILED
	MOVEI	1,100		;PRIMARY INPUT
	JSYS SIBE			;CHARACTERS WAITING?
	    SKIPA		;YES
	JRST	FINSTR		;NO, FIX UP AND RETURN
	SETZM	@-1(P)
	JRST	INS3		;AND USE INCHWL'S LOOP

	
HERE(INSTRS)
	PUSHJ	P,SAVE
	MOVE	LPSA,X33
	PUSHJ	P,REDSTR
	SETOM	@-2(P)		;ASSUME FAILED
	MOVEI	1,100		;RIMARY INPUT
	JSYS SIBE			;CHARACTERS WAITING
	   SKIPA		;YES
	JRST	FINSTR		;NO, FIX UP AND RETURN	
	SETZM	@-2(P)		;INDICATE SUCCESS
	MOVE	B,-1(P)		;GET BREAK CHARACTER	
	JRST	INS2

HERE (CLRBUF)
	PUSH	P,1
	MOVEI	1,100		;PRIMARY INPUT
	JSYS CFIBF			;CLEAR BUFFER
	POP	P,1
	POPJ	P,

HERE (TTYINS) PUSHJ	P,SAVE
	PUSHJ	P,REDSTR	;PREPARE TO MAKE A STRING
	MOVE	LPSA,X33
	SETOM	@-1(P)		;ASSUME NO CHARS
	MOVEI	1,100		;PRIMARY INPUT
	JSYS SIBE			;CHARS WAITING?
	   SKIPA		;YES
	JRST	FINSTR		;NONE WAITING
	JRST	TYIN1		;GO AHEAD


HERE(TTYINL)
HERE (TTYIN)	PUSHJ	P,SAVE
TYIN:	PUSHJ	P,REDSTR		;PREPARE STACK,A,STRNGC FOR A STRING
	MOVE	LPSA,X33		;PREPARE TO RETURN
TYIN1:	SETZM	@-1(P)		;ASSUME NO BREAK CHAR
	SKIPL	E,-2(P)		;TABLE #
	CAILE	E,=18
	  ERR	<TTYIN: THERE ARE ONLY 18 BREAK TABLES>
	HRRZ	TEMP,USER
	ADD	TEMP,E		;TABLE NO(USER)
	MOVEI	Z,1		;FOR TESTING LINE NUMBERS
	SKIPN	LINTBL(TEMP)	;DON'T LET TEST SUCCEED IF
	 MOVEI	 Z,0		;WE'RE TO LET LINE NUMBERS THRU
	MOVE	CHNL,BRKMSK(E)	;GET MASK FOR THIS TABLE
	HRRZ	Y,USER
	ADD	Y,[XWD 1,BRKTBL] ;BRKTBL+RLC(USER)
TTYN:	CAIL	C,=200		;COUNT EXCEEDED?
	   JRST	FINSTR		;YES
	PUSHJ	P,EDICHR	;GET A CHAR
TTYN1:	TDNE	CHNL,@Y		;BREAK OR OMIT?
	JRST	TTYSPC		; YES, FIND OUT WHICH
TTYC:	IDPB	1,D		;PUT IT AWAY
	AOJA	C,TTYN		;COUNT AND CONTINUE
	JRST	FINSTR		;DONE
TTYSPC:	HLLZ	TEMP,@Y		;WHICH?
	TDNN	TEMP,CHNL
	JRST	TTYN		;OMIT
	MOVEM	1,@-1(P)
	MOVE	Y,-2(P)		;WHAT TO DO WITH IT
	ADD	Y,USER
	SKIPN	Y,DSPTBL(Y)
	JRST	FINSTR		;DONE, NO SAVE
	JUMPL	Y,TTYAPP	;APPEND
	PUSH	P,1		;SAVE 
	MOVEI	1,100		;PRIMARY INPUT
	JSYS BKJFN
	  ERR	<CAN'T RETAIN BREAK CHAR FROM TTYIN>,1
	POP	P,1
	JRST	FINSTR		;AND RETURN
TTYAPP:	IDPB	1,D		;COUNT THE BREAK CHAR
	ADDI	C,1		;ONE MORE HAPPY CHAR
	JRST	FINSTR


DSCR INTEGER PROCEDURE TTYUP(INTEGER NEWVALUE)

	Using the RFMOD and SFMOD jsyses, sets lower-to-upper
case conversion to NEWVALUE, returning the oldvalue.  Tests
and modifies bit 31 of the RFMOD word for the primary input
file.	
⊗;
HERE(TTYUP)
	PUSHJ	P,SAVE
	MOVE	LPSA,X22		;SET FOR RETURN
	MOVEI	A,101			;PRIMARY INPUT FILE
	JSYS	RFMOD			;GET THE CURRENT SETTINGS
	SETZ	C,			;ASSUME NOT CURRENTLY SET
	TRNE	B,1B31			;IS IT SET?
	  SETO	C,			;IT WAS
	MOVEM	C,RACS+A(USER)	
	MOVE	C,[TRO B,1B31]		;ASSUME WE WANT TO SET UP
	SKIPN	-1(P)			;DID WE REALLY?
	  MOVE	C,[TRZ B,1B31]		;NO, DONT
	XCT	C
	JSYS	SFMOD
	JRST	RESTR			;AND RETURN


ENDCOM(TTY)
COMPIL(PTY)
ENDCOM(PTY)

COMPIL(FIL,<FILNAM>,<FLSCAN,X22>,<FILNAM SCANNING ROUTINE>)
COMMENT ⊗Filnam ⊗

DSCR FILNAM
CAL PUSHJ
PAR file name string on SP stack
 of form FILENAME<.EXT><[PROJ,PROG]>
RES FNAME(USER) : SIXBIT /filename/
 EXT(USER): SIXBIT /extension,,0/
 0
 PRPN(USER): SIXBIT /PRJ PRG/ (or zero)
SID uses D,X,Y (4-6), REMOVES STRING FROM STACK
⊗

↑↑FILNAM:
	SUB	SP,X22		;ADJUST STACK
	FOR II←1,3 <
	SETZM	FNAME+II(USER)>
	MOVEI	X,FNAME(USER)	;WHERE TO PUT IT
	PUSHJ	P,FLSCAN	;GET FILE NAME
	JUMPE	Y,FLDUN	;FILE NAME ONLY
	CAIE	Y,"."		;EXTENSION?
	JRST	FLEXT		;NO, CHECK PPN
	MOVEI	X,FNAME+1(USER)
	PUSHJ	P,FLSCAN
FLEXT:	JUMPE	Y,FLDUN	;NO PPN SPECIFIED
	CAIE	Y,"["
	JRST	FLERR		;INVALID CHARACTER
	PUSHJ	P,[

	RJUST:	SETZM	PROJ(USER)
		MOVEI	X,PROJ(USER)
		PUSHJ	P,FLSCAN	;GET PROJ OR PROG IN SIXBIT
IFN SIXSW,<
		MOVE	X,PROJ(USER)
		IMULI	D,-6		;SHIFT FACTOR
		LSH	X,(D)		;RIGHT-JUSTIFY THE PROJ OR PROG
>;IF SIXSW (SET IN HEAD, USUALLY CONDITIONED ON NOEXPO)
	
IFE SIXSW,<
		MOVEI	X,0
;;#GT# DCS 5-11-72 ALLOW LARGE OCTAL NUMBERS AT STD DEC SYSTEMS
		MOVE	D,PROJ(USER)	;WAS A HLLZ
;;
	FBACK:	MOVEI	C,0
		LSHC	C,6		;GET A SIXBIT CHAR
		CAIL	C,'0'
		CAILE	C,'7'
		JRST	FLERR		;INVALID OCTAL
		LSH	X,3
		IORI	X,-'0'(C)
		JUMPN	D,FBACK
>;NOT SIXSW (USUALLY CONDITIONED ON EXPO)
	FPOP:	POPJ	P,]

	HRLZM	X,FNAME+3(USER)
	CAIE	Y,","
	JRST	FLERR		;INVALID CHAR
	PUSHJ	P,RJUST		;JUSTIFY(AND CONVERT IF EXPORT) PROG #
	HRRM	X,FNAME+3(USER)
	CAIN	Y,"]"
FLDUN:	AOS	(P)		;SUCCESSFUL
FLERR:	POPJ	P,		;DONE, NOT NECESSARILY RIGHT

ENDCOM(FIL)
COMPIL(FLS,<FLSCAN>,,<FLSCAN ROUTINE>)
COMMENT ⊗Flscan ⊗

DSCR FLSCAN
CAL PUSHJ
PAR X -- addr of destination SIXBIT
 1(SP), 2(SP) -- input string
RES sixbit for next filename, etc in word addressed by X
 break (punctuation) char in Y (0 if string exhausted)
 D,X, input string adjusted
SID only those AC changes listed above (Y, for instance)
⊗

↑↑FLSCAN:  
	HRRZS	1(SP)		;WANT ONLY LENGTH PART
	MOVEI	D,6		;MAX NUMBER PICKED UP
	SETZM	(X)		;ZERO DESTINATION
	HRLI	X,440600	;BYTE POINTER NOW
FLN1:	MOVEI	Y,0		;ASSUME NO STRING LEFT
	SOSGE	1(SP)		;TEST 0-LENGTH STRING
	 POPJ	 P,
	ILDB	Y,2(SP)		;GET BYTE
	CAIE	Y,"."		;CHECK VALID BREAK CHAR
	CAIN	Y,"["
	POPJ	P,
	CAIE	Y,"]"
	CAIN	Y,","
	POPJ	P,
	JUMPE	D,FLN1		;NEED NO MORE CHARS
	TRZN	Y,100		;MOVE 100 BIT TO 40 BIT
	TRZA	Y,40		; TO CONVERT TO SIXBIT
	TRO	Y,40		; (NO CHECKING)
	IDPB	Y,X		;PUT IT AWAY
	SOJA	D,FLN1		;CONTINUE

ENDCOM(FLS)
COMPIL(INP,<INPUT,CHARIN,SINI>
	,<INSET,STRNGC,BRKMSK,X33,GOGTAB,JFNTBL,CDBTBL>
	,<STRING INPUT ROUTINE>)


DSCR  CHAR←CHARIN(CHANNEL)
⊗
HERE(CHARIN)
	BEGIN CHARIN
	PUSH	P,CDB
	PUSH	P,CHNL
	PUSH	P,D
	SKIPL	CHNL,-4(P)
	CAIL	CHNL,JFNSIZE
	   JRST	CHALIT	
	MOVE	CDB,CDBTBL(CHNL)		;CDB
	LDB	D,[POINT 6,OFL(CDB),5]		;GET BYTE SIZE
	CAIE	D,=36				;36-BIT?
	   JRST	CHA7				;TRY 7
	HRRZ	CHNL,JFNTBL(CHNL)		;JFN IN CHNL FOR DOINP
	SKIPN	CHNL
	   JRST	CHABAD
	SKIPE	ENDFL(CDB)			;EOF LOCATION?
	   SETZM @ENDFL(CDB)			;YES, ASSUME GOOD
	SETZM  .SKIP.
	SOSG	ICOWNT(CDB)
	   JRST	[PUSHJ P,DOINP
		 JRST	IN1			;36-BIT RETURN 
	 	 JRST	INB			;7-BIT RETURN	(WITH CHAR IN D)
		 JRST	CHAEOF			;END OF FILE OR ERROR
		]
IN1:	ILDB	D,IBP(CDB)
INB:	MOVE	1,D				;CHAR IN 1
CHARET:	POP	P,D
	POP	P,CHNL
	POP	P,CDB
	SUB	P,X22
	JRST	@2(P)

CHA7:	PUSH	P,2				;SAVE 2
	PUSHJ	P,OPNCH1			;MAKE SURE OPEN
	HRRZ	1,JFNTBL(CDB)
	JSYS	BIN
	JUMPE	2,[JSYS GTSTS
		   TLNE 2,(1B8)
		    JRST CH7EOF			;END OF FILE
	 	   SETZ 2,
		   JRST .+1
		  ]
	MOVE	1,2				;GET CHAR
	POP	P,2				;RESTORE 2
	JRST	CHARET

CH7EOF:	SKIPE	ENDFL(CDB)
	  SETOM	@ENDFL(CDB)
	SETOM  .SKIP.
	POP	P,2

CHAEOF:	
CHABA1:	SETZ	1,				;RETURN NULL BYTE
	JRST	CHARET

CHABAD: ERR <Illegal JFN>,1
	JRST	CHABA1

CHALIT:	PUSH	P,2				;HERE WITH A LITERAL CHAN
	MOVE	1,CHNL
	JSYS	BIN
	MOVE	1,2
	POP	P,2
	JRST	CHARET
	BEND CHARIN
DSCR STRING SIMPLE PROCEDURE SINI(INTEGER JFN,MAXLENGTH,BRKCHAR);
	Reads in a string of characters, terminated by BRKCHAR or	
reaching maxlength, whichever happens first.
⊗

HERE(SINI)
	BEGIN	SINI

	PUSHJ	P,SAVE
	MOVE	LPSA,X44
	VALCHN	1,<-3(P)>,SINBAD
	SKIPE	ENDFL(CDB)		;EOF LOCATION?
	   SETZM @ENDFL(CDB)		;YES, ASSUME NO EOF
	SETZM  .SKIP.
	SKIPG	C,-2(P)			;ANY COUNT?
	  JRST	NULRET
	LDB	B,[POINT 6,OFL(CDB),5]
	CAIE	B,=36			;36-BIT BYTES?
	   JRST	SIN7
;WITH RF(=CHNL) STILL LOADED, IN CASE STRNGC IS CALLED
	PUSH	P,1			;SAVE 1 (WITH JFN)
	MOVE	1,C			;COUNT
	SKIPE	SGLIGN(USER)	
	  PUSHJ	P,INSET
	ADDM	1,REMCHR(USER)		;NEW REMCHR
	SKIPLE	REMCHR(USER)		;COLLECT?
	  PUSHJ	P,STRNGC		;YES
	MOVE	E,TOPBYTE(USER)		;GOOD BYTE-POINTER
	PUSH	SP,[0]
	PUSH	SP,E			;START OF THE STRING
	POP	P,1
	HRRZ	CHNL,1			;JFN IN 1 FOR DOINP
	MOVN	C,C			;NEGATE THE COUNT
IN1:	SOSG	ICOWNT(CDB)
	  JRST	[PUSHJ	P,DOINP
		JRST	IN2		;36-BIT
		JRST SINBAD		;7-BIT??
		JRST	SINDUN]
IN2:	ILDB	D,IBP(CDB)
	JUMPE	D,IN1			;IF NULL KEEP LOOKING
	CAMN	D,-1(P)			;BREAK CHARACTER?
	   JRST	DOBRK			;YES
	IDPB	D,E
IN3:	AOJL	C,IN1			;FALL THRU IF COUNT IS EXHAUSTED

SINDUN:	ADDM	C,REMCHR(USER)		;MAKE REMCHR HONEST	
	MOVEM	E,TOPBYTE(USER)		;SAVE NEW TOPBYTE
	ADD	C,-2(P)			;GET ACTUAL NUMBER OF CHARACTERS TRANSFERRED
	HRROM	C,-1(SP)		;SAVE COUNT FOR USER
	JRST	RESTR

DOBRK:	IDPB	D,E			;SAVE THE BREAK CHARACTER (AS DOES THE SIN JSYS)
	AOJ	C,			;ADD 1 TO THE COUNT
	JRST 	SINDUN			;AND FINISH UP


SIN7:	CAIE	2,7			;MUST BE 7-BIT
	  JRST	SINBAD
;WITH RF (=CHNL) LOADED
	PUSH	P,-2(P)			;MAXLENGTH
	PUSHJ	P,ZSETST
	MOVE	2,1			;BYTE-POINTER IN 2
	HRRZ	1,JFNTBL(CHNL)		;GET THE JFN BACK
	PUSHJ	P,OPNCHK		;MAKE SURE OPEN
	MOVE	3,-2(P)			;MAXLENGTH
	MOVE	4,-1(P)			;OPTIONAL BREAKCHARACTER
	JSYS SIN
	PUSH	P,-2(P)			;MAXLENGTH
	PUSH	P,2			;UPDATED BYTE-POINTER
	PUSHJ	P,ZADJST		;GET STRING ON STACK
	HRRZ	1,JFNTBL(CHNL)		;JFN
	JSYS	GTSTS			;CHECK STATUS
	TLNN	2,(1B8)			;LOOK FOR EOF
	   JRST	RESTR			;NO EOF
	SKIPE	ENDFL(CDB)
	  SETOM	@ENDFL(CDB)
	SETOM  .SKIP.
SINRET:	JRST	RESTR

SINBAD:	ERR <SINI:  Illegal JFN OR ILLEGAL BYTE-SIZE>,1
NULRET:	PUSH	SP,[0]			;RETURN NULL STRING
	PUSH	SP,[0]
	JRST	RESTR
	
	BEND SINI

COMMENT ⊗Input ⊗

DSCR  "STRING"←INPUT(CHANNEL,BREAK TABLE NUMBER);
CAL SAIL
SID NO ACS SAVED BY INPUT!!!!!!
⊗

.IN.:
HERE (INPUT)	
	MOVE	USER,GOGTAB	;GET TABLE POINTER
	MOVEM	RF,RACS+RF(USER);SAVE F-REGISTER
	SKIPE	SGLIGN(USER)
	PUSHJ	P,INSET
	SKIPL	CHNL,-2(P)	;CHANNEL NUMBER
	CAIL	CHNL,JFNSIZE
	  JRST	INPBAD
	MOVE	CDB,CDBTBL(CHNL)
	HRRZ	CHNL,JFNTBL(CHNL)
	SKIPN	CHNL
	  JRST	INPBAD
	LDB	E,[POINT 4,OFL(CDB),9] ;DATA MODE
	SKIPE	ENDFL(CDB)	;EOF LOCATION
	  SETZM	@ENDFL(CDB)	;YES, HELP USER ASSUME NO EOF
	SETZM  .SKIP.
	SKIPE	BRCHAR(CDB)	;BRCHAR LOCATION
	  SETZM	@BRCHAR(CDB)	;ASSUME NO BREAK CHAR
	MOVEI	A,=200		;DEFAULT NO. OF CHARS
	SKIPE	ICOUNT(CDB)	;USER-SPECIFIED COUNT?
	  HRRZ	A,@ICOUNT(CDB)	;MAX COUNT FOR INPUT STRING
	ADDM	A,REMCHR(USER)
	SKIPLE	REMCHR(USER)	;ENOUGH ROOM?
	PUSHJ	P,STRNGC	;NO, TRY TO GET SOME
	SKIPL	C,-1(P)		;GET TABLE #, CHECK IN BOUNDS
	CAILE	C,=18
	  ERR	<IN: THERE ARE ONLY 18 BREAK TABLES>
	HRRZ	TEMP,USER
	ADD	TEMP,C		;TABLE NO(USER)
	MOVEI	Z,1		;FOR TESTING LINE NUMBERS
	SKIPN	LINTBL(TEMP)	;DON'T LET TEST SUCCEED IF
	  MOVEI	 Z,0		;WE'RE TO LET LINE NUMBERS THRU
	MOVN	B,A		;NEGATE MAX CHAR COUNT
	PUSH	SP,[0]		;LEAVE ROOM FOR FIRST STR WORD
	PUSH	SP,TOPBYTE(USER)	;SECOND STRING WORD
	MOVE	FF,BRKMSK(C)	;GET MASK FOR THIS TABLE
	HRRZ	Y,USER
	ADD	Y,[XWD D,BRKTBL] ;BRKTBL+RLC(USER)
	JUMPE	B,DONE1		; BECAUSE THE AOJL WON'T

	TRNE	FF,@BRKCVT(USER) ;DOING UC COERCION?
	TLOA	C,400000	;YES
	TLZ	C,400000	;NO
	
.IN:	SOSG	ICOWNT(CDB)	;BUFFER EMPTY?
	JRST	[ PUSHJ	P,DOINP
		  JRST	IN1	;36-BIT RETURN
		  JRST	INB	;7-BIT RETURN (WITH CHAR IN D)
		  JRST	DONE1	;EOF OR ERROR
		]
IN1:	
	ILDB	D,IBP(CDB)	;GET NEXT CHARACTER
    	TDNE	Z,@IBP(CDB)	;LINE NUMBER (ALWAYS SKIPS IF NOT WORRIED)?
	JRST	INLINN		;YES, GO SEE WHAT TO DO
IN2:
INB:	JUMPE	D,.IN		;ALWAYS IGNORE 0'S
	SKIPN	LINNUM(CDB)	;COUNTING VIA SETPL FUNCTION??
	  JRST	INB1		;NO
	CAIN	D,12		;LINE-FEED?
	  AOS	@LINNUM(CDB)	;INDICATE ANOTHER LINE
	CAIE	D,14		;FORM-FEED?
	  JRST	INB1		;NO
	SKIPE	PAGNUM(CDB)	
	 AOS	@PAGNUM(CDB)	;COUNT PAGES ALSO
	SKIPE	LINNUM(CDB)
	  SETZM @LINNUM(CDB)	;SET LINNUM TO ZERO (NEW PAGE)

INB1:	JUMPGE	C,NOCV.I	;NOT COERCING?
	CAIL	D,"a"		;ONLY COERCE LOWER CASE
	CAILE	D,"z"		;
	JRST	.+2		;SPECIAL RHT "FAST SKIP"
	TRZ	D,40		;MAKE UPPER CASE

NOCV.I:	TDNE	FF,@Y		;MUST WE DO SOMETHING SPECIAL?
	JRST	INSPC		;YES, HANDLE

MOVEC:	IDPB	D,TOPBYTE(USER)	;LENGTHEN STRING
	AOJL	B,.IN		;GET SOME MORE
	JRST	DONE1

INSPC:	HLLZ	TEMP,@Y		;IGNORE OR BREAK?
	TDNN	TEMP,FF		;  (CHOOSE ONE)
	JRST	.IN		;IGNORE

;  BREAK -- STORE BREAK CHAR, FINISH OFF

DONE:	SKIPE	BRCHAR(CDB)	;USER BRCHAR VAR?
	  MOVEM	D,@BRCHAR(CDB)	;STORE BREAK CHAR
	MOVE	Y,-1(P)	;TABLE # AGAIN
	ADD	Y,USER		;RELOCATE
	SKIPN	Y,DSPTBL(Y)	;WHAT TO DO WITH BREAK CHAR?
	JRST	DONE1		;SKIP IT
	JUMPL	Y,APPEND	;ADD TO END OF INPUT STRING

RETAIN:	PUSHJ	P,BACKUP
	JRST	DONE1

APPEND:	IDPB	D,TOPBYTE(USER)	;PUT ON END
	AOJA	B,DONE1		;ONE MORE TO COUNT


;  DONE -- MARK STRING COUNT WORD

DONE1:	ADDM	B,REMCHR(USER)	;GIVE UP THOSE NOT USED
	SKIPN	ICOUNT(CDB)	;USER SUPPLIED COUNT?
	  JRST	[ADDI B,=200	;USER DEFAULT
		 JRST .+2]
	ADD	B,@ICOUNT(CDB)	;HOW MANY DID WE ACTUALLY GET?
;;#GI# DCS 2-5-72 REMOVE TOPSTR
	HRROM	B,-1(SP)	;MARK RESULT, NON-CONSTANT
;;#GI#
	MOVE	RF,RACS+RF(USER);GET F-REGISTER BACK
	SUB	P,X33		;REMOVE INPUT PARAMETER, RETURN ADDRESS
	JRST	@3(P)		;RETURN

;  CAN EITHER DELETE LINE NUMBER (Y GT 0) OR STOP,
;  TELL THE USER (BRCHAR=-1), AND MARK LINE NUMBER
;  NOT A LINE NUMBER FOR NEXT TIME




COMMENT ⊗ BACKUP, DOINP TO BACKUP JFN, DO INPUT. ⊗

;CALL TO HERE WITH A PUSHJ, WITH CDB,CHNL LOADED
↑BACKUP:
	PUSH	P,1
	LDB	1,[POINT 6,OFL(CDB),5]	;BYTE-SIZE
	CAIN 	1,44
	  JRST	BACKU1
;HERE USE BKJFN	
	HRRZ	1,CHNL		;THE JFN
	JSYS BKJFN
	  ERR <BACKUP:  CANNOT DO RETAIN MODE ON THIS FILE>,1
BACRET:	POP	P,1
	POPJ	P,
BACKU1:	SOS	IBP(CDB)
	IBP	IBP(CDB)
	IBP	IBP(CDB)
	IBP	IBP(CDB)
	IBP	IBP(CDB)
	AOS	ICOWNT(CDB)
	JRST	BACRET

	

;CALL TO HERE WITH PUSHJ
;RETURNS +1 FOR 36-BIT INPUT, +2 FOR 7 BIT INPUT (WITH CHAR IN D),
;+3 FOR END OF FILE

↑DOINP:	PUSH	P,1
	PUSH	P,2
	PUSH	P,3
	SKIPE	DECCLZ(CDB)		;CHANNEL CLOSED BY DEC?
	  JRST	[			;YES
		HRRZ	1,CHNL			;JFN
		MOVE	2,OFL(CDB)		;FLAGS
		JSYS	OPENF			;OPEN
		   ERR <OPNCHK:  CANNOT OPENF FILE>
		SETZM	DECCLZ(CDB)
		JRST .+1
		]
OPNOK:	LDB	1,[POINT 4,OFL(CDB),9]	;GET MODE
	CAIN	1,17		;DUMP MODE
	 JRST	 DMPI		; YES
;36 BIT BYTES (SIN) OR 7 BIT (BIN)
	LDB	1,[POINT 6,OFL(CDB),5]	;BYTE-SIZE			
	CAIN	1,44		;36 BIT
	   JRST	DOSIN
	CAIE	1,7		;7-BIT
	   JRST	INPBAD		;ERROR
;HERE TO DO 7-BIT INPUT
DOBIN:	
	HRRZ	1,CHNL	
	JSYS BIN
	JUMPE	2,[JSYS GTSTS	;CHECK STATUS
		   TLNE 2,(1B8)	;EOF?
		      JRST DOIEOF
		   SETZ  2,
		   JRST .+1
		  ]
	MOVE	D,2		;GET THE CHAR IN D
;CHECK IF WE HAVE A TTY
	MOVE	1,DVTYP(CDB)	;GET DEVICE TYPE
	CAIE	1,12		;A TTY?
	  JRST	NOTTTY		;NO
	CAIN	D,32		;A CONTROL-Z?
	  JRST	DOIEOF		;CTRL-Z FROM TTY MEANS EOF
	CAIN	D,37		;PHONEY TENEX EOL?
	  MOVEI D,12		;LINE-FEED
	CAIN	D,33		;ASCII ESCAPE?
	  MOVEI D,ALTMODE	;MAKE ALTMODE
NOTTTY:	SETZM	ICOWNT(CDB)	;0 COUNT (SINCE NO MORE ARE WAITING)
	POP	P,3
	POP	P,2
	POP	P,1
	AOS	(P)		;7-BIT RETURN
	POPJ	P,

DOIEOF:	SKIPE	ENDFL(CDB)	;LOCATION?
	   SETOM @ENDFL(CDB)	;YES, SET IT
	SETOM  .SKIP.
	SETZM	ICOWNT(CDB)	;ZERO THE COUNT
	SETZM	IBP(CDB)	;AND THE BP
	POP	P,3
	POP	P,2
	POP	P,1
	AOS	(P)		;INDICATE EOF
	AOS	(P)
	POPJ	P,

DOSIN:	MOVE	1,CHNL		;JFN	
	SKIPE	DVTYP(CDB)	;DEVICE DSK?
	   JRST	DOSIN1		;NO, USE SIN JSYS
;HERE TO PMAP CORRECT PAGE 
;1, CHNL  HAVE THE JFN, CDB IS LOADED, 2 AND 3 ARE FREE	
	MOVE	2,[XWD 2,11]	;READ TWO WORDS FROM FDB STARTING AT 11
	MOVEI	3,2		;INTO ACS 2 AND 3
	JSYS	GTFDB		;GET THE SIZE OF THE FILE IN 2
	LDB	2,[POINT 6,2,11]	;BYTE SIZE FROM FDB
	PUSH	P,4
	PUSH	P,5
	MOVEI	4,=36
	IDIV	4,2
	IDIV	3,4		;3 NOW HAS THE NUMBER OF 36-BIT BYTES
	SKIPE	4		;REMAINDER?
	  AOJ	3,		;YES, ANOTHER WORD
	POP	P,5
	POP	P,4
	JSYS	RFPTR		;READ CURRENT FILE POINTER INTO 2
	  ERR <DRYROT AT DOINP>
	CAML	2,3		;IS THE FILE POINTER LESS THAN THE SIZE OF THE FILE?
	   JRST [MOVEI	2,STARTPAGE(1);PAGE
		 HRLI	2,400000;
		 SETO	1,
		 SETZ	3,
		 JSYS	PMAP	;RELEASE PAGE		
		 JRST 	DOIEOF	;INDICATE EOF
		]
	SUB	3,2		;CALCULATE THE DIFFERENCE IN WORDS
	CAILE	3,1000
	  MOVEI	3,1000	
	PUSH	P,3		;NO. OF GOOD WORDS ON THIS PAGE, PUSH IT
	IDIVI	2,1000		;CALCULATE THE PAGE NUMBER FOR THIS POINTER
	SKIPE	3		;ANY REMAINDER?	
	  AOJ	2,		;YES, ANOTHER PAGE
	PUSH	P,2		;SAVE THE PAGE WE ARE READING IN
	HRL	1,CHNL
	HRR	1,2		;XWD JFN,PAGE
	MOVEI	2,STARTPAGE(CHNL)
	HRLI	2,400000	;XWD THISFORK, CORE PAGE
	SETO	3,		;FLAG WORD
	JSYS	PMAP
	MOVE	1,CHNL	
	POP	P,2		;GET BACK THE PAGE NO.
	AOJ	2,		;NEXT PAGE	
	LSH	2,=9		;CONVERT TO BYTES
	JSYS	SFPTR		;AND SET THE FILE POINTER
	  ERR <DRYROT AT DOINP>
	POP	P,3		;NUMBER OF GOOD WORDS
	IMULI	3,5		;NUMBER OF CHARACTERS
	JRST	DO36CN		;AND SET UP COUNT, BYTE-POINTERS

;HERE TO DO 36-BIT INPUT WITH THE SIN JSYS
DOSIN1:	MOVEI	2,STARTPAGE(1)
	IMULI	2,1000		;THE CORE ADDRESS
	HRL	3,2
	HRRI	3,1(2)
	SETZM	(2)
	BLT	3,777(2)	;ZERO BUFFER

	HRLI	2,444400	;BYTE-POINTER
	MOVNI	3,1000		;1000 WORDS
	JSYS SIN			;INPUT
	CAMG 3,[-1000]		;SOMETHING RECEIVED?
	  JRST [CAMN	3,[-1000]	;NOTHING AT ALL?
		  JRST	DOIEOF	;NOT A SINGLE WORD
		JRST	.+1
	       ]
       	ADDI	3,1000		;GET NUMBER OF WORDS READ
	IMULI	3,5		;NUMBER OF CHARACTERS
DO36CN:	MOVEM	3,ICOWNT(CDB)	;REMEMBER
	MOVEI	2,STARTPAGE(1)
	IMULI	2,1000
	HRLI	2,440700	;BYTE-POINTER
	MOVEM	2,IBP(CDB)	;REMEMBER
DOIRET:	POP	P,3
	POP	P,2
	POP	P,1
	POPJ	P,


; DUMP MODE -- ESPECIALLY FOR MAGTAPES
DMPI:
	PUSH	P,4		;SAVE AN EXTRA AC
	MOVE	1,CHNL		
	MOVEI	3,STARTPAGE(1)
	IMULI	3,1000		;THE ADDRESS OF THE BUFFER

	HRL	2,3		;ZERO BUFFER
	HRRI	2,1(3)
	SETZM	(3)
	BLT	2,777(3)

	SUBI	3,1
	HRLI	3,-1000		;MAKE AN IOWD
	MOVEI	2,3		;COMMAND LIST STARTS AT 3
	SETZ	4,		;COMMAND LIST ENDS AT 4
	JSYS DUMPI
	  JRST	DMIERR		;AN ERROR
	MOVEI	3,1000*5	;NO. OF CHARACTERS
	POP	P,4		;RESTORE EXTRA AC
	JRST	DO36CN		;SET UP COUNT, BP, AND RETURN

DMIERR:	CAIE	1,600220	;EOF?
	ERR	<INPUT:  DUMP MODE ERROR>

DMIEOF:
	POP	P,4		;FIRST RESTORE 4
	MOVE	1,DVTYP(CDB)
	CAIE	2,3		;MAGTAPE?
	  JRST	DOIEOF		;NO JUST INDICATE EOF
	HRRZ	1,CHNL
	SETZ	2,
	JSYS MTOPR		;RESET STATUS
	JRST	DOIEOF		;AND INDICATE EOF
	

;LINE NUMBER STUFF

INLINN:
NOPGNN:
	SKIPE	SOSNUM(CDB)	;WANT THE NUMBER?
	  JRST 	[MOVE TEMP,@IBP(CDB)	;SAVE IT FOR THE USER
		 MOVEM TEMP,@SOSNUM(CDB)
		 JRST .+1]
	MOVE	TEMP,-1(P)	;GET LINE NUMBER DISPOSITION FLAG,
	ADD	TEMP,USER	;RLC+TABLE
	SKIPGE	TEMP,LINTBL(TEMP) ;LINTBL+RLC+TABLE
	 JRST	 GIVLIN	; WANTS IT NEXT TIME OR SOMETHING

	JSP	TEMP,EATLIN	;TOSS IT OUT, AND 
	JRST	.IN		; CONTINUE

EATLIN:
	AOS	IBP(CDB)	;FORGET IT ENTIRELY
	MOVNI	A,5		;INDICATE SKIPPING SIX
	ADDB	A,ICOWNT(CDB)	;IN COUNT
	JUMPG	A,(TEMP)	;OVERFLOW BUFFER??
	PUSHJ	P,DOINP
	JRST	OKLN		;36-BIT RETURN
	ERR	<INPUT:  7-BIT BYTES CANNOT HAVE LINE NUMBERS>
	JRST	DONE1		;END-OF-FILE
OKLN:	
	IBP	IBP(CDB)	;GET OVER TAB FINALLY
	JRST	(TEMP)		;AND CONTINUE


GIVLIN:	TRNE	TEMP,-1		;WANT LINE NO IN BRCHAR WORD?
	 JRST	 GVLLN		;NO, WANTS IT NEXT TIME.
	SKIPL	TEMP,@IBP(CDB)	;NEGATED LINE NO
	MOVNS	TEMP
	SKIPE	BRCHAR(CDB)	;USER LOCATION?
	MOVEM	TEMP,@BRCHAR(CDB) ;STORE WHERE HE WANTS IT
	JSP	TEMP,EATLIN	;GO EAT UP LINE NUMBER AND
	JRST	DONE1		;FINISH UP
GVLLN:
	SKIPE	BRCHAR(CDB)
	  SETOM	@BRCHAR(CDB)	;TELL THE USER
	AOS	ICOWNT(CDB)	;REVERSE THE SOSLE
	MOVEI	Y,1		;TURN OFF LINE NUMBER 
	ANDCAM	Y,@IBP(CDB)	;  BIT
	MOVSI	Y,070000	;BACK UP BYTE POINTER
	ADDM	Y,IBP(CDB)
	JRST	DONE1		;FINISH OFF IN BAZE OF GORY

INPBAD:	ERR <INPUT:  Illegal JFN OR BAD INPUT>

ENDCOM(INP)
COMPIL(NUM,<REALIN,REALSCAN,INTIN,INTSCAN>
	  ,<SIMIO,SAVE,RESTR,X22,X33,GETCHN,NOTOPN,.CH.,.MT.,.TEN.,BACKUP,DOINP>
	  ,<LOU PAUL'S NUMBER INPUT AND CONVERSION ROUTINES>)
COMMENT ⊗Realin, Realscan ⊗

DSCR REAL←REALIN(CHANNEL NUMBER);
CAL SAIL
⊗

HERE (REALIN)
IFN ALWAYS,<BEGIN NUMIN>

	PUSHJ P,SAVE
	PUSHJ P,NUMIN;		GET NUMBER IN A AND TEN EXPONENT IN C
	MOVE LPSA,X22
	JRST REALFN

DSCR REAL←REALSCAN(@"STRING");
CAL SAIL
⊗

HERE (REALSCAN)
	PUSHJ P,SAVE
	PUSHJ P,STRIN
	MOVE LPSA,X33
REALFN:	SETZ D,;		POS SIGN
	JUMPE A,ADON
	JUMPG A,FPOS
	SETO D,;		NUMBER NEGATIVE
	MOVNS A
FPOS:	;WE NOW HAVE A POSITIVE NUMBER IN A WITH SIGN IN D
	JFFO A,.+1;		NUMBER OF LEADING ZEROS IN B
	ASH A,-1(B);		BIT0=0, BIT1=1
	MOVN X,B;		BIN EXPONENT -2
	JUMPE C,FLO;		IF TEN EXPONENT ZERO THEN FINISH
	JUMPL C,FNEG
	CAIL C,100;		CHECK BOUND OF EXPOENT
	JRST ERROV1
	SETZ Y,
	JRST TEST
FNEG:	MOVNS C
	CAIL C,100
	JRST ERROV1
	MOVEI Y,6
TEST:	TRNE C,1;		DEPENDING ON LOW ORDER BIT OF EXP
	JRST MULT;		EITHER MULTIPLY 
NEXT:	ASH C,-1;		OR DON'T.
	AOJA Y,TEST;		INDEX INTO MULTIPLIER TABLE
MULT:	ADD X,.CH.(Y);		EXPONENT
	MUL A,.MT.(Y)		;MULTIPLY AND NORMALIZE
	TLNE A,200000
	 JRST DTEST
	ASHC A,1
	SOJA X,.+1
DTEST:	SOJG C,NEXT
FLO:	IDIVI A,1B18
	FSC A,255
	FSC B,234
	FADR A,B
	SKIPE D
	MOVNS A
	FSC A,(X);		SCALE
	JRST ALLDON
	SUBTTL	INTIN	INTEGER NUMBER INPUT ROUTINE	LOU PAUL
COMMENT ⊗Intin, Intscan ⊗

DSCR INTEGER←INTIN(CHANNEL NUMBER);
CAL SAIL
⊗

HERE (INTIN)
	;INTEGER NUMBER INPUT ROUTINE RETURNS VALUE IN A
	;USES NUMIN TO PERFORM FREE FIELD SCAN

	PUSHJ P,SAVE
	PUSHJ P,NUMIN;		GET NUMBER IN A, TEN EXPONENT IN C
	MOVE LPSA,X22
	JRST INTFN

DSCR INTEGER←INTSCAN("STRING");
CAL SAIL
⊗

HERE (INTSCAN)
	PUSHJ P,SAVE
	PUSHJ P,STRIN
	MOVE LPSA,X33
INTFN:	JUMPE A,ADON
	JUMPE C,ADON
	JUMPL C,DIVOUT;		IF EXPONENT NEG WE WILL DIVIDE
	CAIL C,13
	JRST ERROV1
	IMUL A,.TEN.(C)
	JRST ALLDON
DIVOUT:	MOVNS C
	CAIL C,13
	JRST [SETZ A,
		JRST ADON ]
	MOVE C,.TEN.(C)
	IDIV A,C
	ASH C,-1
	CAML B,C;		ROUND POSITIVELY
	AOJA A,ALLDON
	MOVNS B
	CAML B,C
	SOJ A,
ALLDON:	JOV ERROV1;		CHECK FOR OVERFLOW
ADON:	MOVEM A,RACS+1(USER)
	JRST RESTR
ERROV1:	PUSHJ P,ERROV
	JRST ADON
	SUBTTL	FREE FIELD NUMBER SCANNER		LOU PAUL
DSCR NUMIN
DES THE COMMON ROUTINE USED BY REALIN, REALSCAN, INTIN, ETC.
⊗
	;NUMIN PERFORMS A FREE FIELD READ AND RETURNS THE MOST SIGNIFICIANT
	;PART OF THE NUMBER IN A AND THE APPROPIATE TENS EXPONENT IN C
	;TAKING CARE OF LEADING ZEROS AND TRUNCATION ETC.
	;SCANNING IS ACCORDING TO THE FOLLOWING BNF
	;<NUMBER>::=<DEL><SIGN><NUM><DEL>
	;<NUM>	::=<NO>|<NO><EXP>|<EXP>
	;<NO>	::=<INTEGER>|<INTEGER>.|
	;	   <INTEGER>.<INTEGER>|.<INTEGER>
	;<INTEGER>::=<DIGIT>|<INTEGER><DIGIT>
	;<EXP>	::=E<SIGN><INTEGER>|@<SIGN><INTEGER>
	;<DIGIT>::=0|1|2|3|4|5|6|7|8|9
	;<SIGN>	::=+|-|<EMPTY>
	;NULL AND CARR. RET. ARE IGNORED.
	;SCANNING IS FACILITATED BY A CHARACTER CLASS TABLE "TAB" AND
	;TWO MACROS AHEAD AND ASTERN. THE LEFT HALF OF THE 200+1 WORD TABLE
	;CONTAINS -1 IF NOT A DIGIT AND THE VALUE OF THE DIGIT IF IT IS A DIGIT
	;THE RIGHT HALF CONTAINS -1 IF A DIGIT AND THE CLASS NUMBER IF NOT.
	;CLASS 0	NULL, CARR RET, NOTHING
	;CLASS 1	.
	;CLASS 2	-
	;CLASS 3	+
	;CLASS 4	@,E
	;CLASS 5	ANY OTHER CHARACETR
	;CLASS 6 	END OF FILE
	;TAB(200) IS USED FOR FND OF FILE
	;MACRO AHEAD IS USED FOR FORWARD SCANNING, ASTERN FOR SCANNING
	;THE STACK CONSISTING OF AC Y WHICH HAS CLASS SYMBOLS SHIFTED INTO IT.
	DEFINE AHEAD(DIG,POINT,MINUS,PLUS,E,CHA,EOF)<
	HRRE X,TAB(D)
	JRST @.+2(X)
	JUMP DIG
	JRST .-4
	JUMP POINT
	JUMP MINUS
	JUMP PLUS
	JUMP E
	JUMP CHA
	JUMP EOF>

	DEFINE ASTERN(NULL,POINT,MINUS,PLUS,E,CHA)<
	SETZ X,
	LSHC X,3
	JRST @.+1(X)
	JUMP NULL
	JUMP POINT
	JUMP MINUS
	JUMP PLUS
	JUMP E
	JUMP CHA
	JUMP CHA>
;NUMIN -- CONTD.

NUMIN:
	SKIPL	CHNL,-2(P)	;
	CAIL	CHNL,JFNSIZE	
	  PUSHJ	P,NUMBAD
	MOVE	CDB,CDBTBL(CHNL)
	SKIPN	CHNL,JFNTBL(CHNL)
	  PUSHJ	P,NUMBAD
	SKIPE	ENDFL(CDB)
	  SETZM	@ENDFL(CDB)
	SETZM	.SKIP.
	SKIPE	BRCHAR(CDB)
	  SETZM	@BRCHAR(CDB)

	MOVE LPSA,[JSP X,NCH]
	MOVEI Z,1;		FOR LINE NUMBER TEST
	PUSHJ P,SCAN
	SKIPE	BRCHAR(CDB)	;USER WANTS BREAK CHARACTER?
	  MOVEM D,@BRCHAR(CDB);	FIX UP BREAK CHARACTER
	SOS	IBP(CDB)		;BACK UP TO GET IT NEXT TIME
	FOR II←1,4 <
	IBP	IBP(CDB)>
	AOS	ICOWNT(CDB)
	POPJ P,

; READ A CHARACTER FROM INPUT FILE -- FOR SCAN.
NCH:	SOSG ICOWNT(CDB);	DECREMENT CHARACTER COUNT
	JRST [PUSHJ P,DOINP
	      JRST	NCH1	;36-BIT RETURN
	      JRST	NCH1.1	;7-BIT RETURN
	      JRST 	NCH7	;EOF OR ERROR
	     ]
NCH1:	ILDB D,IBP(CDB);	LOAD BYTE
	TDNE Z,@IBP(CDB);	CHECK FOR LINE NUMBER
	JRST NCH5
NCH1.1:	SKIPN	LINNUM(CDB)	;WANT SETPL THINGS?
	   JRST	(X)		;NO RETURN
	CAIN	D,12		;LINE FEED?
	   AOS	@LINNUM(CDB)	;YES
	CAIE	D,14		;FORM FEED?
	   JRST	(X)		;NOPE, NOTHING
	SKIPE	PAGNUM(CDB)
	   AOS	@PAGNUM(CDB)	;INCREMENT PAGE COUNTER
	SKIPE	LINNUM(CDB)
	  SETZM	@LINNUM(CDB)	;AND ZERO LINE COUNTER
	JRST (X);		RETURN

NCH7:	MOVEI D,200		;EOF OR DATA ERROR.
	JRST (X)

NCH5:	SKIPE	SOSNUM(CDB)	;WANT SETPL STUFF?
	  JRST	[MOVE	D,@IBP(CDB)
		 MOVEM	D,@SOSNUM(CDB)	;INFORM USER ABOUT LINE NUMBER
		 JRST	.+1]
	AOS IBP(CDB);		WE HAVE A LINE NUMBER
	MOVNI D,5;		MOVE OVER IT
	ADDB D,ICOWNT(CDB)
	SKIPLE D		;NOTHING LEFT?
	  JRST NCH		;DO ANOTHER INPUT
	PUSHJ	P,DOINP		;
	  JRST	NCH6		;36-BIT RETURN -- MUST BE
	  PUSHJ	P,NUMBAD	;IMPOSSIBLE
	  JRST	NCH7		;EOF OR SOME SUCH

NCH6:	SOSG ICOWNT(CDB);	REMOVE TAB
	JRST NCH7		;NONE THERE OR ERROR
	IBP IBP(CDB)
	JRST NCH

;SETUP FOR STRING INPUT (REALSCAN, INTSCAN)
STRIN:	MOVE LPSA,[JSP X,NCHA]
	HRRZ Z,-3(P)
	HRRZ Z,-1(Z)
	HRRZS -3(P)		;SO CAN INDIRECT THROUGH IT.
	PUSHJ P,SCAN
	HRRZ X,-3(P)
	SOS (X)			;BACK UP BYTE POINTER
	FOR II←1,4<
	IBP (X)>
	AOJ Z,
	HRRM Z,-1(X)
	MOVEM D,@-2(P)		;STORE BREAK CHARACTER
	POPJ P,

;READ A CHARACTER ROUTINE FOR STRINGS.
NCHA:	SOJL Z,NCH7
	ILDB D,@-4(P)
	JRST (X)

;SCAN (CALLED BY NUMIN AND STRIN)

SCAN:	JOV .+1
	SETO TEMP,		;FLAG REGISTER.
	SETZ	Y,
	SETZB A,C;		NUMBER		EXPOENT
MORE:	XCT LPSA;		THIS GETS A CHARACTER IN D,200 IF FO EOF
	AHEAD(DIG1,STACK,STACK,STACK,STACK,STACK,DONE)
STACK:	LSHC X,-3;		PUSH SYMBOL ONTO STACK "AC Y"
	JRST MORE

DIG1:	SETZ TEMP,;		FLAG REG.
	ASTERN(INT1,FRA1,SIG1,SIG2,EXP1,INT1)

SIG1:	TRO TEMP,4;		NEGATIVE SIGN
SIG2:	ASTERN(INT1,ERR2,ERR5,ERR5,EXP1,INT1)

EXP1:	MOVEI A,1
	ASTERN(EXP2,ERR2,SIG3,SIG4,ERR1,EXP2)

SIG3:	MOVNS A
SIG4:	ASTERN(EXP2,ERR2,ERR5,ERR5,ERR1,EXP2)

FRA1:	TRO TEMP,1;		DECIMAL POINT
	SOJ C,
	ASTERN(INT1,ERR2,SIG5,SIG6,ERR1,INT1)

SIG5:	TRO TEMP,4;		NEGATIVE SIGN
SIG6:	ASTERN(INT1,ERR2,ERR5,ERR5,ERR1,INT1)

EXP2:	HLRE FF,TAB(D);		FIRST DIGIT
EXP5:	XCT LPSA;		GET NEXT CHARACTER
EXP9:	HLRE B,TAB(D)
	JUMPL B,EEXP;		NEGATIVE IF NOT A DIGIT
	IMULI FF,12
	ADD FF,B
	JRST EXP5

	XCT LPSA
;;#QD# SEE DONE5: BELOW
EEXP:	AHEAD(EXP9,ERR2,DONE5,DONE5,ERR1,EN,EN)
EN:	TRNE TEMP,4;		SIGN OF EXPONENT
	MOVNS FF
	ADD C,FF;		FIX UP EXPONENT
	JOV ERR3

;#QD# CHANGE ALL 'ERR5'S IN AHEAD MACROS DO 'DONE5'S, TO AVOID SNARFING EXTRA
;SIGNS ..... RFS 12-15-73 (TWO PLACES BELOW AND ONE ABOVE ALSO)
DONE5:
DONE:	ANDI D,177
	JUMPGE TEMP,.+2
	SETO D,
	POPJ P,

INT1:	HLRE A,TAB(D);		FIRST DIGIT
	TRNE TEMP,4
	MOVNS A;		NEGATE IF NECESSARY
INT2:	XCT LPSA;		GET NEXT CHARACTER
INT5:	HLRE B,TAB(D)
	JUMPL B,EON;		NEGATIVE IF NOT A NUMBER
	TRNE TEMP,1;		IF PASSED DECIMAL POINT THEN DEC EXP BY ONE
	SOJ C,
	TRNE TEMP,2;		IF ENOUGH DIGITS THEN INC EXP BY ONE
INT3:	AOJA C,INT2
	MOVE X,A
	IMULI A,12
	TRNE TEMP,4;		NEGATE DIGIT IS SIGN NEGATIVE
	MOVNS B
	ADD A,B
	JOV INT4;		CHECK FOR OVERFLOW
	JRST INT2;		IF SO USE LAST VALUE

INT4:	TRO TEMP,2
	MOVE A,X
	JRST INT3

	XCT LPSA
EON:	AHEAD(INT5,DP1,DONE,DONE,EXP6,DONE,DONE)

DP1:	TROE TEMP,1
	JRST ERR2
	XCT LPSA
;#QD# (SEE DONE5: ABOVE)
	AHEAD(INT5,ERR2,DONE5,DONE5,EXP6,DONE,DONE)

EXP6:	SETZ TEMP,
	XCT LPSA
	AHEAD(EXP2,ERR2,EXP7,EXP8,ERR1,ERR1,ERR1)

EXP7:	TRO TEMP,4
EXP8:	XCT LPSA
;#QD# (SEE DONE5: ABOVE)
	AHEAD(EXP2,ERR2,DONE5,DONE5,ERR1,ERR1,ERR1)

ERR1:	ERR(<NUMIN: IMPROPER EXPONENT>,1,RZ)

ERR2:	ERR(<NUMIN: MISPLACED DECIMAL POINT>,1,RZ)

ERR3:	ERR(<NUMIN: EXPONENT OUT OF BOUND>,1,RZ)

ERR5:	ERR(<NUMIN: MISPLACED SIGN>,1,RZ)

ERROV:	ERR(<NUMIN: NUMBER OUT OF BOUND>,1,RZ)

NUMBAD: ERR<NUMIN:  Illegal JFN>
	POPJ	P,

RZ:	SETZ A,
	JRST DONE
;   Character table for SCAN (Realscan,Intscan,Realin,Intin)
TAB:	FOR A IN (0,5,5,5,5,5,5,5)<XWD -1,A
>
	FOR A IN (5,5,5,5,5,0,5,5)<XWD -1,A
>
	FOR A IN (5,5,5,5,5,5,5,5)<XWD -1,A
>
;#QC# MAKE 32 (CONTROL Z) IGNORED
	FOR A IN (5,5,0,5,5,5,5,5)<XWD -1,A
>
	FOR A IN (5,5,5,5,5,5,5,5)<XWD -1,A
>
	FOR A IN (5,5,5,3,5,2,1,5)<XWD -1,A
>
	FOR A IN (0,1,2,3,4,5,6,7,10,11)<XWD A,-1
>
	FOR A IN (5,5,5,5,5,5)<XWD -1,A
>
	FOR A IN (4,5,5,5,5,5,5,5)<XWD -1,A
>
	FOR A IN (5,5,5,5,5,5,5,5)<XWD -1,A
>
	FOR A IN (5,5,5,5,5,5,5,5)<XWD -1,A
>
	FOR A IN (5,5,5,5,5,5,5,5)<XWD -1,A
>
	FOR A IN (5,5,5,5,5,5,5,5)<XWD -1,A
>
	FOR A IN (5,5,5,5,5,5,5,5)<XWD -1,A
>
	FOR A IN (5,5,5,5,5,5,5,5)<XWD -1,A
>
	FOR A IN (5,5,5,5,5,5,5,5)<XWD -1,A
>
	XWD -1,6

ENDCOM(NUM)
COMPIL(TBB,<.CH.,.TEN.,.MT.>,,<TABLES FOR L PAUL'S ROUTINES>)
DSCR DATA TABLES FOR REALIN, INTSCAN, ETC.
⊗

↑↑.CH.:	4
	7
	16
	33
	66
	153
	777777777775
	777777777772
	777777777763
	777777777746
	777777777713
	777777777626
↑↑.MT.:	240000000000
	310000000000
	234200000000
	276570200000
	216067446770
	235613266501
	314631463147
	243656050754
	321556135310
	253630734215
	346453122767
	317542172553
↑↑.TEN.:	1
	=10
	=100
	=1000
	=10000
	=100000
	=1000000
	=10000000
	=100000000
	=1000000000
	=10000000000

ENDCOM(TBB)
IFN ALWAYS,<
	BEND
>;IFN ALWAYS
COMPIL(STDBRK,<STDBRK>,<SAVE,RESTR,GOGTAB,X22>
	,<STDBRK -- STANDARD BREAKSET ROUTINE>)
COMMENT ⊗Stdbrk ⊗

DSCR STDBRK(CHANNEL);
CAL SAIL
⊗

HERE (STDBRK)
	PUSHJ	P,SAVE
	MOVSI	1,100001		
	MOVE	2,[BKTFIL]
	JSYS GTJFN
	  JRST STDERR
	MOVE	2,[XWD 440000,200000]
	JSYS OPENF
	  JRST STDERR
	MOVE	USER,GOGTAB
	MOVSI	2,444400		;BYTE-POINTER
	HRR	2,DSPTBL(USER)		;ADDRESS
	MOVNI	3,=19+=19+=128		;COUNT
	JSYS SIN
	JSYS CLOSF
	  JFCL
STDRET:	MOVE	LPSA,X22
	JRST	RESTR
STDERR: ERR <STDBRK:  CANNOT READ IN FILE>,1
	JRST STDRET



IFN ALWAYS, <BEND IOSER>
DSCR BEND IOSER ⊗
>;TENX